static Type lookupDefaultLiteralType(TypeChecker &TC, DeclContext *dc, StringRef name) { auto lookupOptions = defaultUnqualifiedLookupOptions; if (isa<AbstractFunctionDecl>(dc)) lookupOptions |= NameLookupFlags::KnownPrivate; auto lookup = TC.lookupUnqualified(dc->getModuleScopeContext(), TC.Context.getIdentifier(name), SourceLoc(), lookupOptions); TypeDecl *TD = lookup.getSingleTypeResult(); if (!TD) return Type(); TC.validateDecl(TD); return TD->getDeclaredType(); }
QualType TypeResolver::resolveUnresolved(QualType Q) const { const Type* T = Q.getTypePtr(); switch (Q->getTypeClass()) { case TC_BUILTIN: return Q; case TC_POINTER: { // Dont return new type if not needed const PointerType* P = cast<PointerType>(T); QualType t1 = P->getPointeeType(); QualType Result = resolveUnresolved(t1); if (t1 == Result) return Q; // TODO qualifiers return typeContext.getPointerType(Result); } case TC_ARRAY: { const ArrayType* A = cast<ArrayType>(T); QualType t1 = A->getElementType(); QualType Result = resolveUnresolved(t1); if (t1 == Result) return Q; // TODO qualifiers return typeContext.getArrayType(Result, A->getSizeExpr(), false, A->isIncremental()); } case TC_UNRESOLVED: { const UnresolvedType* U = cast<UnresolvedType>(T); TypeDecl* TD = U->getDecl(); assert(TD); QualType result = TD->getType(); if (Q.isConstQualified()) result.addConst(); if (Q.isVolatileQualified()) result.addVolatile(); return result; } case TC_ALIAS: case TC_STRUCT: case TC_ENUM: case TC_FUNCTION: return Q; case TC_MODULE: assert(0 && "TBD"); return Q; } return Q; }
unsigned TypeResolver::checkUnresolvedType(const UnresolvedType* type, bool used_public) { IdentifierExpr* moduleName = type->getModuleName(); IdentifierExpr* typeName = type->getTypeName(); SourceLocation tLoc = typeName->getLocation(); const std::string& tName = typeName->getName(); Decl* D = 0; if (moduleName) { // mod.type const std::string& mName = moduleName->getName(); const Module* mod = globals.findUsedModule(mName, moduleName->getLocation(), used_public); if (!mod) return 1; Decl* modDecl = globals.findSymbol(mName, moduleName->getLocation(), true, used_public); assert(modDecl); moduleName->setDecl(modDecl); D = globals.findSymbolInModule(tName, tLoc, mod); } else { D = globals.findSymbol(tName, tLoc, true, used_public); } if (!D) return 1; TypeDecl* TD = dyncast<TypeDecl>(D); if (!TD) { StringBuilder name; type->printLiteral(name); Diags.Report(tLoc, diag::err_not_a_typename) << name.c_str(); return 1; } bool external = globals.isExternal(D->getModule()); if (used_public &&!external && !TD->isPublic()) { StringBuilder name; type->printLiteral(name); Diags.Report(tLoc, diag::err_non_public_type) << AnalyserUtils::fullName(TD->getModule()->getName(), TD->getName()); //Diags.Report(tLoc, diag::err_non_public_type) << name; return 1; } D->setUsed(); if (used_public || external) D->setUsedPublic(); typeName->setDecl(TD); return 0; }
QualType TypeResolver::checkCanonicals(Decls& decls, QualType Q, bool set) const { if (Q->hasCanonicalType()) return Q.getCanonicalType(); const Type* T = Q.getTypePtr(); switch (Q->getTypeClass()) { case TC_BUILTIN: return Q; case TC_POINTER: { const PointerType* P = cast<PointerType>(T); QualType t1 = P->getPointeeType(); // Pointee will always be in same TypeContext (file), since it's either built-in or UnresolvedType QualType t2 = checkCanonicals(decls, t1, set); if (!t2.isValid()) return t2; QualType canon; if (t1 == t2) canon = Q; else { canon = typeContext.getPointerType(t2); if (!canon->hasCanonicalType()) canon->setCanonicalType(canon); } assert(Q.isValid()); if (set) P->setCanonicalType(canon); return canon; } case TC_ARRAY: { const ArrayType* A = cast<ArrayType>(T); QualType t1 = A->getElementType(); // NOTE: qualifiers are lost here! QualType t2 = checkCanonicals(decls, t1, set); if (!t2.isValid()) return t2; QualType canon; if (t1 == t2) canon = Q; // NOTE: need size Expr, but set ownership to none else { canon = typeContext.getArrayType(t2, A->getSizeExpr(), false, A->isIncremental()); if (!canon->hasCanonicalType()) canon->setCanonicalType(canon); } if (set) A->setCanonicalType(canon); return canon; } case TC_UNRESOLVED: { const UnresolvedType* U = cast<UnresolvedType>(T); TypeDecl* TD = U->getDecl(); assert(TD); // check if exists if (!checkDecls(decls, TD)) { return QualType(); } QualType canonical = checkCanonicals(decls, TD->getType(), false); if (set) U->setCanonicalType(canonical); return canonical; } case TC_ALIAS: { const AliasType* A = cast<AliasType>(T); if (!checkDecls(decls, A->getDecl())) { return QualType(); } QualType canonical = checkCanonicals(decls, A->getRefType(), set); assert(Q.isValid()); if (set) A->setCanonicalType(canonical); return canonical; } case TC_STRUCT: return Q.getCanonicalType(); case TC_ENUM: { assert(0 && "TODO"); return 0; } case TC_FUNCTION: return Q.getCanonicalType(); case TC_MODULE: assert(0 && "TBD"); return 0; } assert(0); }
int FileScope::checkUserType(Type* type, Expr* id, bool used_public) { // TODO refactor const Package* pkg = 0; switch (id->getKind()) { case EXPR_IDENTIFIER: // unqualified { IdentifierExpr* I = cast<IdentifierExpr>(id); ScopeResult res = findSymbol(I->getName()); if (!res.decl) { Diags.Report(I->getLocation(), diag::err_unknown_typename) << I->getName(); return 1; } if (res.ambiguous) { Diags.Report(I->getLocation(), diag::err_ambiguous_symbol) << I->getName(); // TODO show alternatives return 1; } if (res.external && !res.decl->isPublic()) { Diags.Report(I->getLocation(), diag::err_not_public) << I->getName(); return 1; } TypeDecl* td = dyncast<TypeDecl>(res.decl); if (!td) { Diags.Report(I->getLocation(), diag::err_not_a_typename) << I->getName(); return 1; } if (used_public && !res.external && !td->isPublic()) { Diags.Report(I->getLocation(), diag::err_non_public_type) << I->getName(); return 1; } // ok assert(res.pkg && "pkg should be set"); I->setPackage(res.pkg); I->setDecl(res.decl); type->setRefType(td->getType()); } break; case EXPR_MEMBER: // fully qualified { MemberExpr* M = cast<MemberExpr>(id); Expr* base = M->getBase(); IdentifierExpr* pkg_id = cast<IdentifierExpr>(base); const std::string& pkgName = pkg_id->getName(); // check if package exists pkg = findPackage(pkgName); if (!pkg) { // check if used with alias (then fullname is forbidden) for (PackagesConstIter iter = packages.begin(); iter != packages.end(); ++iter) { const Package* p = iter->second; if (p->getName() == pkgName) { Diags.Report(pkg_id->getLocation(), diag::err_package_has_alias) << pkgName << iter->first; return 1; } } // TODO use function PkgsConstIter iter = allPackages.find(pkgName); if (iter == allPackages.end()) { Diags.Report(pkg_id->getLocation(), diag::err_unknown_package) << pkgName; } else { Diags.Report(pkg_id->getLocation(), diag::err_package_not_used) << pkgName; } return 1; } // check member Expr* member = M->getMember(); IdentifierExpr* member_id = cast<IdentifierExpr>(member); // check Type Decl* symbol = pkg->findSymbol(member_id->getName()); if (!symbol) { Diags.Report(member_id->getLocation(), diag::err_unknown_typename) << M->getFullName(); return 1; } TypeDecl* td = dyncast<TypeDecl>(symbol); if (!td) { Diags.Report(member_id->getLocation(), diag::err_not_a_typename) << M->getFullName(); return 1; } // if external package, check visibility if (isExternal(pkg) && !td->isPublic()) { Diags.Report(member_id->getLocation(), diag::err_not_public) << M->getFullName(); return 1; } if (used_public && !isExternal(pkg) && !td->isPublic()) { Diags.Report(member_id->getLocation(), diag::err_non_public_type) << M->getFullName(); return 1; } // ok member_id->setPackage(pkg); type->setRefType(td->getType()); } break; default: assert(0); } return 0; }