//===--- NameLookup.cpp - Swift Name Lookup Routines ----------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements interfaces for performing name lookup. // //===----------------------------------------------------------------------===// #include "swift/AST/NameLookup.h" #include "swift/AST/AST.h" #include "swift/AST/ASTVisitor.h" using namespace swift; MemberLookup::MemberLookup(Type BaseTy, Identifier Name, Module &M) { MemberName = Name; VisitedSet Visited; doIt(BaseTy, M, Visited); } /// doIt - Lookup a member 'Name' in 'BaseTy' within the context /// of a given module 'M'. This operation corresponds to a standard "dot" /// lookup operation like "a.b" where 'this' is the type of 'a'. This /// operation is only valid after name binding. void MemberLookup::doIt(Type BaseTy, Module &M, VisitedSet &Visited) { typedef MemberLookupResult Result; // Just look through l-valueness. It doesn't affect name lookup. if (LValueType *LV = BaseTy->getAs()) BaseTy = LV->getObjectType(); // Type check metatype references, as in "some_type.some_member". These are // special and can't have extensions. if (MetaTypeType *MTT = BaseTy->getAs()) { // The metatype represents an arbitrary named type: dig through to the // declared type to see what we're dealing with. Type Ty = MTT->getTypeDecl()->getDeclaredType(); // Just perform normal dot lookup on the type with the specified // member name to see if we find extensions or anything else. For example, // type SomeTy.SomeMember can look up static functions, and can even look // up non-static functions as well (thus getting the address of the member). doIt(Ty, M, Visited); return; } // Lookup module references, as on some_module.some_member. These are // special and can't have extensions. if (ModuleType *MT = BaseTy->getAs()) { SmallVector Decls; MT->getModule()->lookupValue(Module::AccessPathTy(), MemberName, NLKind::QualifiedLookup, Decls); for (ValueDecl *VD : Decls) Results.push_back(Result::getMetatypeMember(VD)); return; } // If the base is a protocol, see if this is a reference to a declared // protocol member. if (ProtocolType *PT = BaseTy->getAs()) { if (!Visited.insert(PT->getDecl())) return; for (auto Inherited : PT->getDecl()->getInherited()) doIt(Inherited, M, Visited); for (auto Member : PT->getDecl()->getMembers()) { if (ValueDecl *VD = dyn_cast(Member)) { if (VD->getName() != MemberName) continue; if (isa(VD) || isa(VD) || isa(VD)) { Results.push_back(Result::getExistentialMember(VD)); } else { assert(isa(VD) && "Unhandled protocol member"); Results.push_back(Result::getMetatypeMember(VD)); } } } return; } // If the base is a protocol composition, see if this is a reference to a // declared protocol member in any of the protocols. if (auto PC = BaseTy->getAs()) { for (auto Proto : PC->getProtocols()) doIt(Proto, M, Visited); return; } // Check to see if this is a reference to a tuple field. if (TupleType *TT = BaseTy->getAs()) { // If the field name exists, we win. Otherwise, if the field name is a // dollarident like $4, process it as a field index. int FieldNo = TT->getNamedElementId(MemberName); if (FieldNo != -1) { Results.push_back(MemberLookupResult::getTupleElement(FieldNo)); } else { StringRef NameStr = MemberName.str(); if (NameStr.startswith("$")) { unsigned Value = 0; if (!NameStr.substr(1).getAsInteger(10, Value) && Value < TT->getFields().size()) Results.push_back(MemberLookupResult::getTupleElement(Value)); } } } // Look in any extensions that add methods to the base type. SmallVector ExtensionMethods; M.lookupMembers(BaseTy, MemberName, ExtensionMethods); for (ValueDecl *VD : ExtensionMethods) { if (TypeDecl *TAD = dyn_cast(VD)) { Results.push_back(Result::getMetatypeMember(TAD)); continue; } if (FuncDecl *FD = dyn_cast(VD)) { if (FD->isStatic()) Results.push_back(Result::getMetatypeMember(FD)); else Results.push_back(Result::getMemberFunction(FD)); continue; } if (OneOfElementDecl *OOED = dyn_cast(VD)) { Results.push_back(Result::getMetatypeMember(OOED)); continue; } assert((isa(VD) || isa(VD)) && "Unexpected extension member"); Results.push_back(Result::getMemberProperty(VD)); } } static Type makeSimilarLValue(Type objectType, Type lvalueType, ASTContext &Context) { LValueType::Qual qs = cast(lvalueType)->getQualifiers(); return LValueType::get(objectType, qs, Context); } static Expr *buildTupleElementExpr(Expr *Base, SourceLoc DotLoc, SourceLoc NameLoc, unsigned FieldIndex, ASTContext &Context) { Type BaseTy = Base->getType(); bool IsLValue = false; if (LValueType *LV = BaseTy->getAs()) { IsLValue = true; BaseTy = LV->getObjectType(); } Type FieldType = BaseTy->castTo()->getElementType(FieldIndex); if (IsLValue) FieldType = makeSimilarLValue(FieldType, Base->getType(), Context); if (DotLoc.isValid()) return new (Context) SyntacticTupleElementExpr(Base, DotLoc, FieldIndex, NameLoc, FieldType); return new (Context) ImplicitThisTupleElementExpr(Base, FieldIndex, NameLoc, FieldType); } /// createResultAST - Build an AST to represent this lookup, with the /// specified base expression. Expr *MemberLookup::createResultAST(Expr *Base, SourceLoc DotLoc, SourceLoc NameLoc, ASTContext &Context) { assert(isSuccess() && "Can't create a result if we didn't find anything"); // Handle the case when we found exactly one result. if (Results.size() == 1) { MemberLookupResult R = Results[0]; bool IsMetatypeBase = Base->getType()->is(); switch (R.Kind) { case MemberLookupResult::TupleElement: if (IsMetatypeBase) break; return buildTupleElementExpr(Base, DotLoc, NameLoc, R.TupleFieldNo, Context); case MemberLookupResult::MemberFunction: { if (IsMetatypeBase) { Expr *RHS = new (Context) DeclRefExpr(R.D, NameLoc, R.D->getTypeOfReference()); return new (Context) DotSyntaxBaseIgnoredExpr(Base, DotLoc, RHS); } Expr *Fn = new (Context) DeclRefExpr(R.D, NameLoc, R.D->getTypeOfReference()); return new (Context) DotSyntaxCallExpr(Fn, DotLoc, Base); } case MemberLookupResult::MemberProperty: { if (IsMetatypeBase) break; VarDecl *Var = cast(R.D); return new (Context) MemberRefExpr(Base, DotLoc, Var, NameLoc); } case MemberLookupResult::MetatypeMember: { Expr *RHS = new (Context) DeclRefExpr(R.D, NameLoc, R.D->getTypeOfReference()); return new (Context) DotSyntaxBaseIgnoredExpr(Base, DotLoc, RHS); } case MemberLookupResult::ExistentialMember: return new (Context) ExistentialMemberRefExpr(Base, DotLoc, R.D, NameLoc); } Expr *BadExpr = new (Context) UnresolvedDotExpr(Base, DotLoc, MemberName, NameLoc); return BadExpr; } // If we have an ambiguous result, build an overload set. SmallVector ResultSet; // This is collecting a mix of static and normal functions. We won't know // until after overload resolution whether we actually need 'this'. for (MemberLookupResult X : Results) { assert(X.Kind != MemberLookupResult::TupleElement); ResultSet.push_back(X.D); } return OverloadedMemberRefExpr::createWithCopy(Base, DotLoc, ResultSet, NameLoc); } struct FindLocalVal : public StmtVisitor { SourceLoc Loc; Identifier Name; ValueDecl *MatchingValue; FindLocalVal(SourceLoc Loc, Identifier Name) : Loc(Loc), Name(Name), MatchingValue(nullptr) {} bool IntersectsRange(SourceRange R) { return R.Start.Value.getPointer() <= Loc.Value.getPointer() && R.End.Value.getPointer() >= Loc.Value.getPointer(); } void checkValueDecl(ValueDecl *D) { if (D->getName() == Name) { assert(!MatchingValue); MatchingValue = D; } } void checkPattern(Pattern *Pat) { switch (Pat->getKind()) { case PatternKind::Tuple: for (auto &field : cast(Pat)->getFields()) checkPattern(field.getPattern()); return; case PatternKind::Paren: return checkPattern(cast(Pat)->getSubPattern()); case PatternKind::Typed: return checkPattern(cast(Pat)->getSubPattern()); case PatternKind::Named: return checkValueDecl(cast(Pat)->getDecl()); // Handle non-vars. case PatternKind::Any: return; } } void checkTranslationUnit(TranslationUnit *TU) { for (Decl *D : TU->Decls) { if (TopLevelCodeDecl *TLCD = dyn_cast(D)) { if (Stmt *S = TLCD->getBody().dyn_cast()) visit(S); } } } void visitBreakStmt(BreakStmt *) {} void visitContinueStmt(ContinueStmt *) {} void visitSemiStmt(SemiStmt *) {} void visitErrorStmt(ErrorStmt *) {} void visitAssignStmt(AssignStmt *) {} void visitReturnStmt(ReturnStmt *) {} void visitIfStmt(IfStmt * S) { visit(S->getThenStmt()); if (S->getElseStmt()) visit(S->getElseStmt()); } void visitWhileStmt (WhileStmt *S) { visit(S->getBody()); } void visitForStmt (ForStmt *S) { if (!IntersectsRange(S->getSourceRange())) return; visit(S->getBody()); if (MatchingValue) return; for (Decl *D : S->getInitializerVarDecls()) { if (ValueDecl *VD = dyn_cast(D)) checkValueDecl(VD); } } void visitForEachStmt (ForEachStmt *S) { if (!IntersectsRange(S->getSourceRange())) return; visit(S->getBody()); if (MatchingValue) return; checkPattern(S->getPattern()); } void visitBraceStmt(BraceStmt *S) { if (!IntersectsRange(S->getSourceRange())) return; for (auto elem : S->getElements()) { if (Stmt *S = elem.dyn_cast()) visit(S); } if (MatchingValue) return; for (auto elem : S->getElements()) { if (Decl *D = elem.dyn_cast()) { if (ValueDecl *VD = dyn_cast(D)) checkValueDecl(VD); } } } }; UnqualifiedLookup::UnqualifiedLookup(Identifier Name, DeclContext *DC, SourceLoc Loc) { typedef UnqualifiedLookupResult Result; DeclContext *ModuleDC = DC; while (!ModuleDC->isModuleContext()) ModuleDC = ModuleDC->getParent(); Module &M = *cast(ModuleDC); // If we are inside of a method, check to see if there are any ivars in scope, // and if so, whether this is a reference to one of them. while (!DC->isModuleContext()) { ValueDecl *BaseDecl = 0; Type ExtendedType; if (FuncExpr *FE = dyn_cast(DC)) { // Look for local variables; normally, the parser resolves these // for us, but it can't do the right thing inside local types. if (Loc.isValid()) { FindLocalVal localVal(Loc, Name); localVal.visit(FE->getBody()); if (!localVal.MatchingValue) { for (Pattern *P : FE->getParamPatterns()) localVal.checkPattern(P); } if (localVal.MatchingValue) { Results.push_back(Result::getLocalDecl(localVal.MatchingValue)); return; } } FuncDecl *FD = FE->getDecl(); if (FD && FD->getExtensionType() && !FD->isStatic()) { ExtendedType = FD->getExtensionType(); BaseDecl = FD->getImplicitThisDecl(); DC = DC->getParent(); } } else if (ExtensionDecl *ED = dyn_cast(DC)) { ExtendedType = ED->getExtendedType(); BaseDecl = ExtendedType->castTo()->getDecl(); } else if (NominalTypeDecl *ND = dyn_cast(DC)) { ExtendedType = ND->getDeclaredType(); BaseDecl = ND; } if (BaseDecl) { MemberLookup Lookup(ExtendedType, Name, M); for (auto Result : Lookup.Results) { switch (Result.Kind) { case MemberLookupResult::MemberProperty: Results.push_back(Result::getMemberProperty(BaseDecl, Result.D)); break; case MemberLookupResult::MemberFunction: Results.push_back(Result::getMemberFunction(BaseDecl, Result.D)); break; case MemberLookupResult::MetatypeMember: Results.push_back(Result::getMetatypeMember(BaseDecl, Result.D)); break; case MemberLookupResult::ExistentialMember: Results.push_back(Result::getExistentialMember(BaseDecl, Result.D)); break; case MemberLookupResult::TupleElement: llvm_unreachable("Can't have context with tuple type"); } } if (Lookup.isSuccess()) return; } DC = DC->getParent(); } if (Loc.isValid()) { if (TranslationUnit *TU = dyn_cast(&M)) { // Look for local variables in top-level code; normally, the parser // resolves these for us, but it can't do the right thing for // local types. // FIXME: Need to suppress this for cases in name binding where we know // it's a waste of time. FindLocalVal localVal(Loc, Name); localVal.checkTranslationUnit(TU); if (localVal.MatchingValue) { Results.push_back(Result::getLocalDecl(localVal.MatchingValue)); return; } } } // Do a local lookup within the current module. llvm::SmallVector CurModuleResults; M.lookupValue(Module::AccessPathTy(), Name, NLKind::UnqualifiedLookup, CurModuleResults); for (ValueDecl *VD : CurModuleResults) Results.push_back(Result::getModuleMember(VD)); // The builtin module has no imports. if (isa(M)) return; TranslationUnit &TU = cast(M); bool NameBindingLookup = TU.ASTStage == Module::Parsed; llvm::SmallPtrSet CurModuleTypes; for (ValueDecl *VD : CurModuleResults) { // If we find a type in the current module, don't look into any // imported modules. if (isa(VD)) return; if (!NameBindingLookup) CurModuleTypes.insert(VD->getType()->getCanonicalType()); } // Scrape through all of the imports looking for additional results. // FIXME: Implement DAG-based shadowing rules. llvm::SmallPtrSet Visited; for (auto &ImpEntry : TU.getImportedModules()) { if (!Visited.insert(ImpEntry.second)) continue; SmallVector ImportedModuleResults; ImpEntry.second->lookupValue(ImpEntry.first, Name, NLKind::UnqualifiedLookup, ImportedModuleResults); for (ValueDecl *VD : ImportedModuleResults) { if (NameBindingLookup || isa(VD) || !CurModuleTypes.count(VD->getType()->getCanonicalType())) { Results.push_back(Result::getModuleMember(VD)); } } } for (const auto &ImpEntry : TU.getImportedModules()) if (ImpEntry.second->Name == Name) { Results.push_back(Result::getModuleName(ImpEntry.second)); break; } } TypeDecl* UnqualifiedLookup::getSingleTypeResult() { if (Results.size() != 1 || !Results.back().hasValueDecl() || !isa(Results.back().getValueDecl())) return nullptr; return cast(Results.back().getValueDecl()); }