diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 8f4bf7c531712..2ccda2c3f31d4 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -648,9 +648,17 @@ class alignas(1 << TypeAlignInBits) TypeBase { /// with a class type. bool mayHaveSuperclass(); - /// \brief Determine whether this type may have nested types, which holds for - /// nominal types, existentials and archetypes. - bool mayHaveMemberTypes() { + /// \brief Determine whether this type can be used as a base type for AST + /// name lookup, which is the case for nominal types, protocol compositions + /// and archetypes. + /// + /// Generally, the static vs instanec and mutating vs nonmutating distinction + /// is handled elsewhere, so metatypes, lvalue types and inout types are not + /// allowed here. + /// + /// Similarly, tuples formally have members, but this does not go through + /// name lookup. + bool mayHaveMembers() { return (is() || is() || isExistentialType() || diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index fc6d99be64c75..459d481ee0fe2 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -224,7 +224,7 @@ struct SynthesizedExtensionAnalyzer::Implementation { // the extension to the interface types of the base type's // declaration. TypeSubstitutionMap subMap; - if (!BaseType->isAnyExistentialType()) + if (!BaseType->isExistentialType()) subMap = BaseType->getContextSubstitutions(Ext); auto *M = DC->getParentModule(); @@ -453,7 +453,9 @@ void PrintOptions::clearSynthesizedExtension() { } TypeTransformContext::TypeTransformContext(Type T) - : BaseType(T.getPointer()) {} + : BaseType(T.getPointer()) { + assert(T->mayHaveMembers()); +} TypeTransformContext::TypeTransformContext(NominalTypeDecl *NTD) : BaseType(NTD->getDeclaredTypeInContext().getPointer()), Nominal(NTD) {} @@ -984,8 +986,9 @@ class PrintAST : public ASTVisitor { Type OldType = CurrentType; if (CurrentType && (Old != nullptr || Options.PrintAsMember)) { if (auto *NTD = dyn_cast(D)) { - CurrentType = CurrentType->getTypeOfMember( - Options.CurrentModule, NTD, nullptr); + CurrentType = NTD->getDeclaredInterfaceType().subst( + Options.CurrentModule, + CurrentType->getContextSubstitutions(NTD->getDeclContext())); } } @@ -1259,7 +1262,7 @@ void PrintAST::printSingleDepthOfGenericSignature( ModuleDecl *M = nullptr; if (CurrentType) { - if (!CurrentType->isAnyExistentialType()) { + if (!CurrentType->isExistentialType()) { auto *DC = Current->getInnermostDeclContext()->getInnermostTypeContext(); subMap = CurrentType->getContextSubstitutions(DC); M = DC->getParentModule(); diff --git a/lib/AST/NameLookup.cpp b/lib/AST/NameLookup.cpp index 9b13448c4151c..97dd541ffe485 100644 --- a/lib/AST/NameLookup.cpp +++ b/lib/AST/NameLookup.cpp @@ -1316,17 +1316,6 @@ bool DeclContext::lookupQualified(Type type, } }; - // Look through lvalue and inout types. - type = type->getLValueOrInOutObjectType(); - - // Look through metatypes. - if (auto metaTy = type->getAs()) - type = metaTy->getInstanceType(); - - // Look through DynamicSelf. - if (auto dynamicSelf = type->getAs()) - type = dynamicSelf->getSelfType(); - // Look for module references. if (auto moduleTy = type->getAs()) { Module *module = moduleTy->getModule(); @@ -1438,6 +1427,8 @@ bool DeclContext::lookupQualified(Type type, } } } + } else { + llvm_unreachable("Bad type for qualified lookup"); } // Allow filtering of the visible declarations based on various diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 21efa3093d3bd..70308810637b8 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3099,23 +3099,15 @@ Type TypeBase::getSuperclassForDecl(const ClassDecl *baseClass, } TypeSubstitutionMap TypeBase::getContextSubstitutions(const DeclContext *dc) { + assert(dc->isTypeContext()); + Type baseTy(this); - // Ignore lvalues in the base type. - Type baseTy(getRValueType()); - - // Look through the metatype; it has no bearing on the result. - if (auto metaBase = baseTy->getAs()) { - baseTy = metaBase->getInstanceType()->getRValueType(); - } + assert(!baseTy->isLValueType() && !baseTy->is()); // The resulting set of substitutions. Always use this to ensure we // don't miss out on NRVO anywhere. TypeSubstitutionMap substitutions; - // Look through non-type contexts. - while (!dc->isTypeContext()) - dc = dc->getParent(); - // If the member is part of a protocol or extension thereof, we need // to substitute in the type of Self. if (dc->getAsProtocolOrProtocolExtensionContext()) { @@ -3127,19 +3119,24 @@ TypeSubstitutionMap TypeBase::getContextSubstitutions(const DeclContext *dc) { return substitutions; } + // If we found a member of a concrete type from a protocol extension, + // get the superclass out of the archetype. + if (auto *archetypeTy = baseTy->getAs()) + baseTy = archetypeTy->getSuperclass(); + // Extract the lazy resolver. LazyResolver *resolver = dc->getASTContext().getLazyResolver(); // Find the superclass type with the context matching that of the member. // // FIXME: Do this in the caller? - if (baseTy->getAnyNominal()) { - auto *ownerNominal = dc->getAsNominalTypeOrNominalTypeExtensionContext(); - if (auto *ownerClass = dyn_cast(ownerNominal)) - baseTy = baseTy->getSuperclassForDecl(ownerClass, resolver); + assert(baseTy->getAnyNominal()); - assert(ownerNominal == baseTy->getAnyNominal()); - } + auto *ownerNominal = dc->getAsNominalTypeOrNominalTypeExtensionContext(); + if (auto *ownerClass = dyn_cast(ownerNominal)) + baseTy = baseTy->getSuperclassForDecl(ownerClass, resolver); + + assert(ownerNominal == baseTy->getAnyNominal()); // If the base type isn't specialized, there's nothing to substitute. if (!baseTy->isSpecialized()) @@ -3177,8 +3174,7 @@ TypeSubstitutionMap TypeBase::getContextSubstitutions(const DeclContext *dc) { continue; } - // We're done. - break; + llvm_unreachable("Bad base type"); } return substitutions; diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp index ce47bf801257a..78f391d39417e 100644 --- a/lib/IDE/CodeCompletion.cpp +++ b/lib/IDE/CodeCompletion.cpp @@ -1975,8 +1975,13 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { Type ContextTy = VD->getDeclContext()->getDeclaredInterfaceType(); if (ContextTy) { // Look through lvalue types and metatypes - Type MaybeNominalType = (*ExprType)->getRValueType() - ->getRValueInstanceType(); + Type MaybeNominalType = (*ExprType)->getRValueType(); + + if (auto Metatype = MaybeNominalType->getAs()) + MaybeNominalType = Metatype->getInstanceType(); + + if (auto SelfType = MaybeNominalType->getAs()) + MaybeNominalType = SelfType->getSelfType(); // For optional protocol requirements and dynamic dispatch, // strip off optionality from the base type, but only if @@ -1989,6 +1994,12 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { if (MaybeNominalType->isAnyObject()) return T; + // FIXME: Sometimes ExprType is the type of the member here, + // and not the type of the base. That is inconsistent and + // should be cleaned up. + if (!MaybeNominalType->mayHaveMembers()) + return T; + // For everything else, substitute in the base type. auto Subs = MaybeNominalType->getMemberSubstitutions(VD); @@ -2865,23 +2876,24 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { if (auto *NTD = dyn_cast(D)) { addNominalTypeRef(NTD, Reason); - addConstructorCallsForType(NTD->getInterfaceType(), NTD->getName(), - Reason); + addConstructorCallsForType(NTD->getDeclaredInterfaceType(), + NTD->getName(), Reason); return; } if (auto *TAD = dyn_cast(D)) { addTypeAliasRef(TAD, Reason); auto type = TAD->mapTypeIntoContext(TAD->getUnderlyingTypeLoc().getType()); - addConstructorCallsForType(type, TAD->getName(), Reason); + if (type->mayHaveMembers()) + addConstructorCallsForType(type, TAD->getName(), Reason); return; } if (auto *GP = dyn_cast(D)) { addGenericTypeParamRef(GP, Reason); for (auto *protocol : GP->getConformingProtocols()) - addConstructorCallsForType(protocol->getInterfaceType(), GP->getName(), - Reason); + addConstructorCallsForType(protocol->getDeclaredInterfaceType(), + GP->getName(), Reason); return; } @@ -2934,23 +2946,24 @@ class CompletionLookup final : public swift::VisibleDeclConsumer { if (auto *NTD = dyn_cast(D)) { addNominalTypeRef(NTD, Reason); - addConstructorCallsForType(NTD->getInterfaceType(), NTD->getName(), - Reason); + addConstructorCallsForType(NTD->getDeclaredInterfaceType(), + NTD->getName(), Reason); return; } if (auto *TAD = dyn_cast(D)) { addTypeAliasRef(TAD, Reason); auto type = TAD->mapTypeIntoContext(TAD->getDeclaredInterfaceType()); - addConstructorCallsForType(type, TAD->getName(), Reason); + if (type->mayHaveMembers()) + addConstructorCallsForType(type, TAD->getName(), Reason); return; } if (auto *GP = dyn_cast(D)) { addGenericTypeParamRef(GP, Reason); for (auto *protocol : GP->getConformingProtocols()) - addConstructorCallsForType(protocol->getInterfaceType(), GP->getName(), - Reason); + addConstructorCallsForType(protocol->getDeclaredInterfaceType(), + GP->getName(), Reason); return; } diff --git a/lib/SILGen/SILGenMaterializeForSet.cpp b/lib/SILGen/SILGenMaterializeForSet.cpp index 53345c2d2277b..6734d430b691d 100644 --- a/lib/SILGen/SILGenMaterializeForSet.cpp +++ b/lib/SILGen/SILGenMaterializeForSet.cpp @@ -385,7 +385,8 @@ struct MaterializeForSetEmitter { /// Given part of the witness's interface type, produce its /// substitution according to the witness substitutions. CanType getSubstWitnessInterfaceType(CanType type) { - auto subs = SubstSelfType->getMemberSubstitutions(WitnessStorage); + auto subs = SubstSelfType->getRValueInstanceType() + ->getMemberSubstitutions(WitnessStorage); return type.subst(SGM.SwiftModule, subs)->getCanonicalType(); } diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 1b848a99cef60..40402cc5893a4 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -5852,7 +5852,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, auto toObjType = toType->getLValueOrInOutObjectType(); // Conversion to/from UnresolvedType (looking through @lvalue or inout). - if (fromObjType->is() || toObjType->is()) + if (fromObjType->hasUnresolvedType() || toObjType->hasUnresolvedType()) return cs.cacheType(new (tc.Context) UnresolvedTypeConversionExpr(expr, toType)); diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index d2f5bc68ea405..e37867af1d9e5 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -1219,6 +1219,9 @@ static bool findGenericSubstitutions(DeclContext *dc, Type paramType, } }; + if (paramType->hasError()) + return false; + GenericVisitor visitor(dc, archetypesMap); return visitor.match(paramType, actualArgType); } @@ -1474,6 +1477,38 @@ CalleeCandidateInfo::evaluateCloseness(UncurriedCandidate candidate, return { closeness, {}}; } +/// Rewrite any type parameters in the specified type with UnresolvedType. +static Type replaceTypeParametersWithUnresolved(Type ty) { + if (!ty) return ty; + + if (!ty->hasTypeParameter() && !ty->hasArchetype()) return ty; + + auto &ctx = ty->getASTContext(); + + return ty.transform([&](Type type) -> Type { + if (type->is() || + type->isTypeParameter()) + return ctx.TheUnresolvedType; + return type; + }); +} + +/// Rewrite any type variables & archetypes in the specified type with +/// UnresolvedType. +static Type replaceTypeVariablesWithUnresolved(Type ty) { + if (!ty) return ty; + + if (!ty->hasTypeVariable()) return ty; + + auto &ctx = ty->getASTContext(); + + return ty.transform([&](Type type) -> Type { + if (type->isTypeVariableOrMember()) + return ctx.TheUnresolvedType; + return type; + }); +} + void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, bool implicitDotSyntax) { fn = fn->getValueProvidingExpr(); @@ -1552,23 +1587,28 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn, collectCalleeCandidates(AE->getFn(), /*implicitDotSyntax=*/AE->getMemberOperatorRef()); - // If this is a DotSyntaxCallExpr, then the callee is a method, and the - // argument list of this apply is the base being applied to the method. - // If we have a type for that, capture it so that we can calculate a - // substituted type, which resolves many generic arguments. - Type baseType; - if (isa(AE) && - !isUnresolvedOrTypeVarType(AE->getArg()->getType())) - baseType = AE->getArg()->getType()->getLValueOrInOutObjectType(); - // If we found a candidate list with a recursive walk, try adjust the curry // level for the applied subexpression in this call. if (!candidates.empty()) { + // If this is a DotSyntaxCallExpr, then the callee is a method, and the + // argument list of this apply is the base being applied to the method. + // If we have a type for that, capture it so that we can calculate a + // substituted type, which resolves many generic arguments. + Type baseType; + if (isa(AE) && + !isUnresolvedOrTypeVarType(AE->getArg()->getType())) + baseType = AE->getArg()->getType()->getLValueOrInOutObjectType(); + for (auto &C : candidates) { C.level += 1; + baseType = replaceTypeVariablesWithUnresolved(baseType); + // Compute a new substituted type if we have a base type to apply. if (baseType && C.level == 1 && C.getDecl()) { + baseType = baseType + ->getLValueOrInOutObjectType() + ->getRValueInstanceType(); C.entityType = baseType->getTypeOfMember(CS->DC->getParentModule(), C.getDecl(), nullptr); C.substituted = true; @@ -1755,22 +1795,19 @@ CalleeCandidateInfo::CalleeCandidateInfo(Type baseType, // it to get a simpler and more concrete type. // if (baseType) { - auto substType = baseType; + auto substType = replaceTypeVariablesWithUnresolved(baseType); + if (substType) + substType = substType + ->getLValueOrInOutObjectType() + ->getRValueInstanceType(); + // If this is a DeclViaUnwrappingOptional, then we're actually looking // through an optional to get the member, and baseType is an Optional or // Metatype. if (cand.getKind() == OverloadChoiceKind::DeclViaUnwrappedOptional) { - bool isMeta = false; - if (auto MTT = substType->getAs()) { - isMeta = true; - substType = MTT->getInstanceType(); - } - // Look through optional or IUO to get the underlying type the decl was // found in. substType = substType->getAnyOptionalObjectType(); - if (isMeta && substType) - substType = MetatypeType::get(substType); } else if (cand.getKind() != OverloadChoiceKind::Decl) { // Otherwise, if it is a remapping we can't handle, don't try to compute // a substitution. @@ -2292,8 +2329,8 @@ bool FailureDiagnosis::diagnoseGeneralMemberFailure(Constraint *constraint) { anchor = typeCheckArbitrarySubExprIndependently(anchor, TCC_AllowLValue); if (!anchor) return true; - auto baseTy = anchor->getType(); - auto baseObjTy = baseTy->getRValueType(); + auto baseTy = anchor->getType()->getLValueOrInOutObjectType(); + auto baseObjTy = baseTy; // If the base type is an IUO, look through it. Odds are, the code is not // trying to find a member of it. @@ -3067,7 +3104,7 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){ // contain a member var 'boolValue', now does not convert to Bool. This block // tries to add a specific diagnosis/fixit to explicitly invoke 'boolValue'. if (toType->isBool() && - fromType->mayHaveMemberTypes()) { + fromType->mayHaveMembers()) { auto LookupResult = CS->TC.lookupMember(CS->DC, fromType, DeclName(CS->TC.Context.getIdentifier("boolValue"))); if (!LookupResult.empty()) { @@ -3366,22 +3403,6 @@ static void eraseOpenedExistentials(Expr *&expr) { expr = expr->walk(ExistentialEraser()); } -/// Rewrite any type variables & archetypes in the specified type with -/// UnresolvedType. -static Type replaceArchetypesAndTypeVarsWithUnresolved(Type ty) { - if (!ty) return ty; - - auto &ctx = ty->getASTContext(); - - return ty.transform([&](Type type) -> Type { - if (type->isTypeVariableOrMember() || - type->is() || - type->isTypeParameter()) - return ctx.TheUnresolvedType; - return type; - }); -} - /// Unless we've already done this, retypecheck the specified subexpression on /// its own, without including any contextual constraints or parent expr /// nodes. This is more likely to succeed than type checking the original @@ -3414,9 +3435,8 @@ Expr *FailureDiagnosis::typeCheckChildIndependently( convertType = FT->getResult(); // Replace archetypes and type parameters with UnresolvedType. - if (convertType->hasTypeVariable() || convertType->hasArchetype() || - convertType->hasTypeParameter()) - convertType = replaceArchetypesAndTypeVarsWithUnresolved(convertType); + convertType = replaceTypeParametersWithUnresolved(convertType); + convertType = replaceTypeVariablesWithUnresolved(convertType); // If the conversion type contains no info, drop it. if (convertType->is() || diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index af3fc9b3c0552..6157032f1d651 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2644,9 +2644,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, return result; } - if (instanceTy->isTypeParameter()) - return MemberLookupResult(); - // Okay, start building up the result list. MemberLookupResult result; result.OverallResult = MemberLookupResult::HasResults; @@ -2676,7 +2673,12 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, result.ViableCandidates.push_back(OverloadChoice(baseTy, fieldIdx)); return result; } - + + if (auto *selfTy = instanceTy->getAs()) + instanceTy = selfTy->getSelfType(); + + if (!instanceTy->mayHaveMembers()) + return result; // If we have a simple name, determine whether there are argument // labels we can use to restrict the set of lookup results. @@ -2741,7 +2743,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, // extensions cannot yet define designated initializers. lookupOptions -= NameLookupFlags::PerformConformanceCheck; - LookupResult ctors = TC.lookupConstructors(DC, baseObjTy, lookupOptions); + LookupResult ctors = TC.lookupConstructors(DC, instanceTy, lookupOptions); if (!ctors) return result; // No result. @@ -2831,7 +2833,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, } // Look for members within the base. - LookupResult &lookup = lookupMember(baseObjTy, memberName); + LookupResult &lookup = lookupMember(instanceTy, memberName); // The set of directly accessible types, which is only used when // we're performing dynamic lookup into an existential type. @@ -3017,10 +3019,11 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, if (result.ViableCandidates.empty() && isMetatype && constraintKind == ConstraintKind::UnresolvedValueMember) { if (auto objectType = instanceTy->getAnyOptionalObjectType()) { - LookupResult &optionalLookup = lookupMember(MetatypeType::get(objectType), - memberName); - for (auto result : optionalLookup) - addChoice(result, /*bridged*/false, /*isUnwrappedOptional=*/true); + if (objectType->mayHaveMembers()) { + LookupResult &optionalLookup = lookupMember(objectType, memberName); + for (auto result : optionalLookup) + addChoice(result, /*bridged*/false, /*isUnwrappedOptional=*/true); + } } } @@ -3045,7 +3048,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName, // This is only used for diagnostics, so always use KnownPrivate. lookupOptions |= NameLookupFlags::KnownPrivate; - auto lookup = TC.lookupMember(DC, baseObjTy->getCanonicalType(), + auto lookup = TC.lookupMember(DC, instanceTy, memberName, lookupOptions); for (auto cand : lookup) { // If the result is invalid, skip it. diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index cfed438307130..9e67c7d44b88b 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -214,10 +214,7 @@ LookupResult &ConstraintSystem::lookupMember(Type base, DeclName name) { result = std::move(lookup); // If we aren't performing dynamic lookup, we're done. - auto instanceTy = base->getRValueType(); - if (auto metaTy = instanceTy->getAs()) - instanceTy = metaTy->getInstanceType(); - auto protoTy = instanceTy->getAs(); + auto protoTy = base->getAs(); if (!*result || !protoTy || !protoTy->getDecl()->isSpecificProtocol( @@ -1568,15 +1565,7 @@ Type ConstraintSystem::simplifyType(Type type) { if (newBase.getPointer() == depMemTy->getBase().getPointer()) return type; - Type lookupBaseType = newBase; - - // Look through an inout type. - if (auto inout = lookupBaseType->getAs()) - lookupBaseType = inout->getObjectType(); - - // Look through a metatype. - if (auto metatype = lookupBaseType->getAs()) - lookupBaseType = metatype->getInstanceType(); + Type lookupBaseType = newBase->getLValueOrInOutObjectType(); // If the new base is still something we can't handle, just build a // new dependent member type. @@ -1592,9 +1581,12 @@ Type ConstraintSystem::simplifyType(Type type) { auto assocType = depMemTy->getAssocType(); assert(depMemTy->getAssocType()); - auto result = lookupBaseType->getTypeOfMember( - DC->getParentModule(), assocType, &TC, - assocType->getDeclaredInterfaceType()); + if (!lookupBaseType->mayHaveMembers()) return type; + + auto result = assocType->getDeclaredInterfaceType() + .subst(DC->getParentModule(), + lookupBaseType->getContextSubstitutions( + assocType->getDeclContext())); // FIXME: Record failure somehow? if (!result) return type; diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 68a37e7138712..1ef1b1562120e 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -521,13 +521,16 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E, // non-existential type and has any initializers. auto eTy = E->getType(); bool isExistential = false; - if (auto metaTy = eTy->getAs()) - isExistential = metaTy->getInstanceType()->isAnyExistentialType(); - if (!isExistential && - !eTy->is() && - !TC.lookupConstructors(const_cast(DC), eTy).empty()) { - TC.diagnose(E->getEndLoc(), diag::add_parens_to_type) - .fixItInsertAfter(E->getEndLoc(), "()"); + if (auto metaTy = E->getType()->getAs()) { + auto instanceTy = metaTy->getInstanceType(); + isExistential = instanceTy->isExistentialType(); + if (!isExistential && + instanceTy->mayHaveMembers() && + !TC.lookupConstructors(const_cast(DC), + instanceTy).empty()) { + TC.diagnose(E->getEndLoc(), diag::add_parens_to_type) + .fixItInsertAfter(E->getEndLoc(), "()"); + } } // Add fix-it to insert ".self". @@ -3319,7 +3322,8 @@ class ObjCSelectorWalker : public ASTWalker { auto nominal = method->getDeclContext()->getAsNominalTypeOrNominalTypeExtensionContext(); auto result = TC.lookupMember(const_cast(DC), - nominal->getInterfaceType(), lookupName, + nominal->getDeclaredInterfaceType(), + lookupName, (defaultMemberLookupOptions | NameLookupFlags::KnownPrivate)); diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index e4136a55d13f0..aaa371b7e5ce9 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1152,14 +1152,13 @@ void AttributeChecker::checkApplicationMainAttribute(DeclAttribute *attr, ProtocolDecl *ApplicationDelegateProto = nullptr; if (KitModule) { auto lookupOptions = defaultUnqualifiedLookupOptions; - lookupOptions |= NameLookupFlags::OnlyTypes; lookupOptions |= NameLookupFlags::KnownPrivate; - auto lookup = TC.lookupUnqualified(KitModule, Id_ApplicationDelegate, - SourceLoc(), - lookupOptions); - ApplicationDelegateProto = dyn_cast_or_null( - lookup.getSingleTypeResult()); + auto lookup = TC.lookupUnqualifiedType(KitModule, Id_ApplicationDelegate, + SourceLoc(), + lookupOptions); + if (lookup.size() == 1) + ApplicationDelegateProto = dyn_cast(lookup[0]); } if (!ApplicationDelegateProto || diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index bf7741050f432..e1fd79aa63fc2 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -2048,17 +2048,17 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) { // types of existentials. // // We will diagnose it later. - if (!sequenceType->isExistentialType()) { + if (!sequenceType->isExistentialType() && + (sequenceType->mayHaveMembers() || + sequenceType->isTypeVariableOrMember())) { ASTContext &ctx = tc.Context; auto iteratorAssocType = cast( sequenceProto->lookupDirect(ctx.Id_Iterator).front()); - iteratorType = sequenceType->getTypeOfMember( - cs.DC->getParentModule(), - iteratorAssocType, - &tc, - iteratorAssocType->getDeclaredInterfaceType()); + iteratorType = iteratorAssocType->getDeclaredInterfaceType() + .subst(cs.DC->getParentModule(), + sequenceType->getContextSubstitutions(sequenceProto)); if (iteratorType) { auto iteratorProto = diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index d69aaf614ea53..1d82bf30828bf 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -5343,7 +5343,6 @@ class DeclChecker : public DeclVisitor { // one. auto attempt = OverrideCheckingAttempt::PerfectMatch; SmallVector matches; - auto superclassMetaTy = MetatypeType::get(superclass); DeclName name = decl->getFullName(); bool hadExactMatch = false; LookupResult members; @@ -5387,7 +5386,7 @@ class DeclChecker : public DeclVisitor { lookupOptions -= NameLookupFlags::ProtocolMembers; lookupOptions -= NameLookupFlags::PerformConformanceCheck; - members = TC.lookupMember(decl->getDeclContext(), superclassMetaTy, + members = TC.lookupMember(decl->getDeclContext(), superclass, name, lookupOptions); } diff --git a/lib/Sema/TypeCheckExprObjC.cpp b/lib/Sema/TypeCheckExprObjC.cpp index f2e0351d8e216..cedc21b176fb2 100644 --- a/lib/Sema/TypeCheckExprObjC.cpp +++ b/lib/Sema/TypeCheckExprObjC.cpp @@ -330,8 +330,8 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, Type newType; if (lookupType && !lookupType->isAnyObject()) { - newType = lookupType->getTypeOfMember(dc->getParentModule(), type, - this); + newType = lookupType->getTypeOfMember(dc->getParentModule(), type, this, + type->getDeclaredInterfaceType()); } else { newType = type->getDeclaredInterfaceType(); } diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index aab0e4cf8a404..547d418366eff 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -99,10 +99,6 @@ namespace { /// \param foundInType The type through which we found the /// declaration. void add(ValueDecl *found, ValueDecl *base, Type foundInType) { - // If we only want types, AST name lookup should not yield anything else. - assert(!Options.contains(NameLookupFlags::OnlyTypes) || - isa(found)); - ConformanceCheckOptions conformanceOptions; if (Options.contains(NameLookupFlags::KnownPrivate)) conformanceOptions |= ConformanceCheckFlags::InExpression; @@ -181,7 +177,7 @@ LookupResult TypeChecker::lookupUnqualified(DeclContext *dc, DeclName name, name, dc, this, options.contains(NameLookupFlags::KnownPrivate), loc, - options.contains(NameLookupFlags::OnlyTypes), + /*OnlyTypes=*/false, options.contains(NameLookupFlags::ProtocolMembers), options.contains(NameLookupFlags::IgnoreAccessibility)); @@ -218,24 +214,46 @@ SmallVector TypeChecker::lookupUnqualifiedType(DeclContext *dc, DeclName name, SourceLoc loc, NameLookupOptions options) { + SmallVector decls; + + // Try lookup without ProtocolMembers first. UnqualifiedLookup lookup( name, dc, this, options.contains(NameLookupFlags::KnownPrivate), loc, /*OnlyTypes=*/true, - options.contains(NameLookupFlags::ProtocolMembers), + /*ProtocolMembers=*/false, options.contains(NameLookupFlags::IgnoreAccessibility)); - - LookupResult result; - SmallVector decls; for (auto found : lookup.Results) decls.push_back(cast(found.getValueDecl())); + + if (decls.empty() && + options.contains(NameLookupFlags::ProtocolMembers)) { + // Try again, this time with protocol members. + // + // FIXME: Fix the problem where if NominalTypeDecl::getAllProtocols() + // is called too early, we start resolving extensions -- even those + // which do provide conformances. + UnqualifiedLookup lookup( + name, dc, this, + options.contains(NameLookupFlags::KnownPrivate), + loc, + /*OnlyTypes=*/true, + /*ProtocolMembers=*/true, + options.contains(NameLookupFlags::IgnoreAccessibility)); + + for (auto found : lookup.Results) + decls.push_back(cast(found.getValueDecl())); + } + return decls; } LookupResult TypeChecker::lookupMember(DeclContext *dc, Type type, DeclName name, NameLookupOptions options) { + assert(type->mayHaveMembers()); + LookupResult result; NLOptions subOptions = NL_QualifiedDefault; if (options.contains(NameLookupFlags::KnownPrivate)) @@ -244,19 +262,8 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, subOptions |= NL_DynamicLookup; if (options.contains(NameLookupFlags::IgnoreAccessibility)) subOptions |= NL_IgnoreAccessibility; - if (options.contains(NameLookupFlags::OnlyTypes)) - subOptions |= NL_OnlyTypes; - - // Dig out the type that we'll actually be looking into, and determine - // whether it is a nominal type. - Type lookupType = type; - if (auto lvalueType = lookupType->getAs()) { - lookupType = lvalueType->getObjectType(); - } - if (auto metaType = lookupType->getAs()) { - lookupType = metaType->getInstanceType(); - } - NominalTypeDecl *nominalLookupType = lookupType->getAnyNominal(); + + NominalTypeDecl *nominalLookupType = type->getAnyNominal(); if (options.contains(NameLookupFlags::ProtocolMembers)) subOptions |= NL_ProtocolMembers; @@ -265,9 +272,6 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, subOptions &= ~NL_RemoveOverridden; subOptions &= ~NL_RemoveNonVisible; - // We can't have tuple types here; they need to be handled elsewhere. - assert(!type->is()); - // Local function that performs lookup. auto doLookup = [&]() { result.clear(); @@ -278,7 +282,7 @@ LookupResult TypeChecker::lookupMember(DeclContext *dc, dc->lookupQualified(type, name, subOptions, this, lookupResults); for (auto found : lookupResults) { - builder.add(found, nominalLookupType, lookupType); + builder.add(found, nominalLookupType, type); } }; @@ -310,10 +314,6 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, NameLookupOptions options) { LookupTypeResult result; - // Structural types do not have member types. - if (!type->mayHaveMemberTypes()) - return result; - // Look for members with the given name. SmallVector decls; NLOptions subOptions = NL_QualifiedDefault | NL_OnlyTypes; diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 0ca99c1566209..a542949bbf724 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -134,12 +134,11 @@ static Type getObjectiveCNominalType(TypeChecker &TC, NameLookupOptions lookupOptions = defaultMemberLookupOptions | - NameLookupFlags::KnownPrivate | - NameLookupFlags::OnlyTypes; - if (auto result = TC.lookupMember(dc, ModuleType::get(module), TypeName, - lookupOptions)) { - for (auto decl : result) { - if (auto nominal = dyn_cast(decl.Decl)) { + NameLookupFlags::KnownPrivate; + if (auto result = TC.lookupMemberType(dc, ModuleType::get(module), TypeName, + lookupOptions)) { + for (auto pair : result) { + if (auto nominal = dyn_cast(pair.first)) { cache = nominal->getDeclaredType(); return cache; } @@ -775,7 +774,6 @@ static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc, NameLookupOptions relookupOptions = lookupOptions; relookupOptions |= NameLookupFlags::KnownPrivate; relookupOptions |= NameLookupFlags::IgnoreAccessibility; - relookupOptions |= NameLookupFlags::OnlyTypes; auto inaccessibleResults = tc.lookupUnqualifiedType(lookupDC, comp->getIdentifier(), comp->getIdLoc(), relookupOptions); @@ -831,6 +829,12 @@ static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc, } // Qualified lookup case. + if (!parentType->mayHaveMembers()) { + tc.diagnose(comp->getIdLoc(), diag::invalid_member_type, + comp->getIdentifier(), parentType) + .highlight(parentRange); + return ErrorType::get(tc.Context); + } // Try ignoring access control. NameLookupOptions relookupOptions = lookupOptions; @@ -883,12 +887,9 @@ static Type diagnoseUnknownType(TypeChecker &tc, DeclContext *dc, NameLookupOptions memberLookupOptions = lookupOptions; memberLookupOptions |= NameLookupFlags::IgnoreAccessibility; memberLookupOptions |= NameLookupFlags::KnownPrivate; - memberLookupOptions -= NameLookupFlags::OnlyTypes; - if (parentType->mayHaveMemberTypes()) { - memberLookup = tc.lookupMember(dc, parentType, comp->getIdentifier(), - memberLookupOptions); - } + memberLookup = tc.lookupMember(dc, parentType, comp->getIdentifier(), + memberLookupOptions); // Looks like this is not a member type, but simply a member of parent type. if (!memberLookup.empty()) { @@ -1028,12 +1029,8 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC, return nullptr; NameLookupOptions lookupOptions = defaultUnqualifiedLookupOptions; - lookupOptions |= NameLookupFlags::OnlyTypes; if (options.contains(TR_KnownNonCascadingDependency)) lookupOptions |= NameLookupFlags::KnownPrivate; - // FIXME: Eliminate this once we can handle finding protocol members - // in resolveTypeInContext. - lookupOptions -= NameLookupFlags::ProtocolMembers; auto globals = TC.lookupUnqualifiedType(lookupDC, comp->getIdentifier(), comp->getIdLoc(), @@ -1229,8 +1226,10 @@ static Type resolveNestedIdentTypeComponent( if (options.contains(TR_ExtensionBinding) || options.contains(TR_InheritanceClause)) lookupOptions -= NameLookupFlags::ProtocolMembers; - auto memberTypes = TC.lookupMemberType(DC, parentTy, comp->getIdentifier(), - lookupOptions); + LookupTypeResult memberTypes; + if (parentTy->mayHaveMembers()) + memberTypes = TC.lookupMemberType(DC, parentTy, comp->getIdentifier(), + lookupOptions); // Name lookup was ambiguous. Complain. // FIXME: Could try to apply generic arguments first, and see whether diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 456375e0b0a5b..368fa5a07e3c4 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -246,11 +246,9 @@ enum class NameLookupFlags { /// Whether to perform 'dynamic' name lookup that finds @objc /// members of any class or protocol. DynamicLookup = 0x08, - /// Whether we're only looking for types. - OnlyTypes = 0x10, /// Whether to ignore access control for this lookup, allowing inaccessible /// results to be returned. - IgnoreAccessibility = 0x20, + IgnoreAccessibility = 0x10, }; /// A set of options that control name lookup. diff --git a/test/Generics/associated_types.swift b/test/Generics/associated_types.swift index 282856104b8a1..50fae7c3a0dcc 100644 --- a/test/Generics/associated_types.swift +++ b/test/Generics/associated_types.swift @@ -21,8 +21,7 @@ struct Z : Fooable { var a : AssocType // expected-warning {{variable 'a' was never used; consider replacing with '_' or removing it}} {{9-10=_}} } - // FIXME: We should be able to find this. - func blarg() -> AssocType {} // expected-error{{use of undeclared type 'AssocType'}} + func blarg() -> AssocType {} func wonka() -> Z.AssocType {} } diff --git a/test/decl/ext/generic.swift b/test/decl/ext/generic.swift index a70281dbcca1e..a478406bf218b 100644 --- a/test/decl/ext/generic.swift +++ b/test/decl/ext/generic.swift @@ -152,3 +152,9 @@ struct S4: P4 { } extension S4 where T : P5 {} + +struct S5 { + init(_: Q) { } +} + +extension S5 : P4 {} diff --git a/test/decl/typealias/protocol.swift b/test/decl/typealias/protocol.swift index 85a115f5f8897..253ec3bfe47ef 100644 --- a/test/decl/typealias/protocol.swift +++ b/test/decl/typealias/protocol.swift @@ -154,9 +154,9 @@ struct T5 : P5 { var v2: P5.T2 // expected-error {{typealias 'T2' can only be used with a concrete type or generic parameter base}} var v3: P5.X // expected-error {{typealias 'X' can only be used with a concrete type or generic parameter base}} - // FIXME: Unqualified reference to typealias from a protocol conformance - var v4: T1 // expected-error {{use of undeclared type 'T1'}} - var v5: T2 // expected-error {{use of undeclared type 'T2'}} + // Unqualified reference to typealias from a protocol conformance + var v4: T1 // OK + var v5: T2 // OK // Qualified reference var v6: T5.T1 // OK @@ -178,8 +178,7 @@ extension P7 { struct S7 : P7 { typealias A = Int - // FIXME - func inTypeContext(y: Y) // expected-error {{use of undeclared type 'Y'}} + func inTypeContext(y: Y) { } func inExpressionContext() { _ = Y.self diff --git a/test/expr/expressions.swift b/test/expr/expressions.swift index 27595b9446910..0828286e680db 100644 --- a/test/expr/expressions.swift +++ b/test/expr/expressions.swift @@ -645,13 +645,18 @@ func lvalue_processing() { struct Foo { func method() {} + mutating func mutatingMethod() {} } func test() { var x = Foo() + let y = Foo() + + // FIXME: Bad diagnostics // rdar://15708430 - (&x).method() // expected-error {{'inout Foo' is not convertible to 'Foo'}} + (&x).method() // expected-error {{type of expression is ambiguous without more context}} + (&x).mutatingMethod() // expected-error {{cannot use mutating member on immutable value of type 'inout Foo'}} } diff --git a/validation-test/compiler_crashers/28442-swift-typebase-getrvaluetype.swift b/validation-test/compiler_crashers_fixed/28442-swift-typebase-getrvaluetype.swift similarity index 87% rename from validation-test/compiler_crashers/28442-swift-typebase-getrvaluetype.swift rename to validation-test/compiler_crashers_fixed/28442-swift-typebase-getrvaluetype.swift index 38dd4933d348e..1e3169218bc6b 100644 --- a/validation-test/compiler_crashers/28442-swift-typebase-getrvaluetype.swift +++ b/validation-test/compiler_crashers_fixed/28442-swift-typebase-getrvaluetype.swift @@ -5,6 +5,6 @@ // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// RUN: not --crash %target-swift-frontend %s -typecheck +// RUN: not %target-swift-frontend %s -typecheck // REQUIRES: asserts var f={var f=[]f.init diff --git a/validation-test/compiler_crashers/28561-input-hastypevariable-output-hastypevariable.swift b/validation-test/compiler_crashers_fixed/28561-input-hastypevariable-output-hastypevariable.swift similarity index 87% rename from validation-test/compiler_crashers/28561-input-hastypevariable-output-hastypevariable.swift rename to validation-test/compiler_crashers_fixed/28561-input-hastypevariable-output-hastypevariable.swift index 083ebce8ed139..21c58fb3606a1 100644 --- a/validation-test/compiler_crashers/28561-input-hastypevariable-output-hastypevariable.swift +++ b/validation-test/compiler_crashers_fixed/28561-input-hastypevariable-output-hastypevariable.swift @@ -5,6 +5,6 @@ // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// RUN: not --crash %target-swift-frontend %s -emit-ir +// RUN: not %target-swift-frontend %s -emit-ir // REQUIRES: asserts Set.init(""3