From 52eb66f8f44a2adb495f8ff97a79b308419fb24b Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 20 Aug 2018 17:15:32 -0700 Subject: [PATCH 1/7] [Type checker] Eliminate simple, pointless uses of TypeChecker from TypeResolver Do the easy part of separating the TypeResolver, which is chiefly responsible for turning TypeReprs into Types, from the TypeChecker. --- lib/Sema/TypeCheckType.cpp | 157 +++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 7caf8c52539b0..9b547f7d295ba 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1576,7 +1576,8 @@ namespace { public: TypeResolver(TypeChecker &tc, TypeResolution resolution) - : TC(tc), Context(tc.Context), resolution(resolution), + : TC(tc), Context(resolution.getDeclContext()->getASTContext()), + resolution(resolution), DC(resolution.getDeclContext()) { } @@ -1584,6 +1585,11 @@ namespace { Type resolveType(TypeRepr *repr, TypeResolutionOptions options); private: + template + InFlightDiagnostic diagnose(ArgTypes &&...Args) const { + auto &diags = Context.Diags; + return diags.diagnose(std::forward(Args)...); + } Type resolveAttributedType(AttributedTypeRepr *repr, TypeResolutionOptions options); @@ -1670,7 +1676,7 @@ Type TypeResolver::resolveType(TypeRepr *repr, TypeResolutionOptions options) { // If we know the type representation is invalid, just return an // error type. - if (repr->isInvalid()) return ErrorType::get(TC.Context); + if (repr->isInvalid()) return ErrorType::get(Context); // Strip the "is function input" bits unless this is a type that knows about // them. @@ -1780,10 +1786,9 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr, TypeResolutionOptions options) { // Convenience to grab the source range of a type attribute. - auto getTypeAttrRangeWithAt = [](TypeChecker &TC, SourceLoc attrLoc) { + auto getTypeAttrRangeWithAt = [](ASTContext &ctx, SourceLoc attrLoc) { return SourceRange(attrLoc.getAdvancedLoc(-1), - Lexer::getLocForEndOfToken(TC.Context.SourceMgr, - attrLoc)); + Lexer::getLocForEndOfToken(ctx.SourceMgr, attrLoc)); }; @@ -1833,8 +1838,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, // Check for @thick. if (attrs.has(TAK_thick)) { if (storedRepr) - TC.diagnose(repr->getStartLoc(), - diag::sil_metatype_multiple_reprs); + diagnose(repr->getStartLoc(), diag::sil_metatype_multiple_reprs); storedRepr = MetatypeRepresentation::Thick; attrs.clearAttribute(TAK_thick); @@ -1843,8 +1847,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, // Check for @objc_metatype. if (attrs.has(TAK_objc_metatype)) { if (storedRepr) - TC.diagnose(repr->getStartLoc(), - diag::sil_metatype_multiple_reprs); + diagnose(repr->getStartLoc(), diag::sil_metatype_multiple_reprs); storedRepr = MetatypeRepresentation::ObjC; attrs.clearAttribute(TAK_objc_metatype); @@ -1873,7 +1876,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, auto checkUnsupportedAttr = [&](TypeAttrKind attr) { if (attrs.has(attr)) { - TC.diagnose(attrs.getLoc(attr), diag::attribute_not_supported); + diagnose(attrs.getLoc(attr), diag::attribute_not_supported); attrs.clearAttribute(attr); } }; @@ -1907,8 +1910,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, if (!fnRepr) { if (attrs.has(TAK_autoclosure)) { - TC.diagnose(attrs.getLoc(TAK_autoclosure), - diag::autoclosure_function_type); + diagnose(attrs.getLoc(TAK_autoclosure), diag::autoclosure_function_type); attrs.clearAttribute(TAK_autoclosure); } // Fall through to diagnose below. @@ -1926,8 +1928,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, auto calleeConvention = ParameterConvention::Direct_Unowned; if (attrs.has(TAK_callee_owned)) { if (attrs.has(TAK_callee_guaranteed)) { - TC.diagnose(attrs.getLoc(TAK_callee_owned), - diag::sil_function_repeat_convention, /*callee*/ 2); + diagnose(attrs.getLoc(TAK_callee_owned), + diag::sil_function_repeat_convention, /*callee*/ 2); } calleeConvention = ParameterConvention::Direct_Owned; } else if (attrs.has(TAK_callee_guaranteed)) { @@ -1952,8 +1954,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, SILFunctionType::Representation::WitnessMethod) .Default(None); if (!parsedRep) { - TC.diagnose(attrs.getLoc(TAK_convention), - diag::unsupported_sil_convention, attrs.getConvention()); + diagnose(attrs.getLoc(TAK_convention), + diag::unsupported_sil_convention, attrs.getConvention()); rep = SILFunctionType::Representation::Thin; } else { rep = *parsedRep; @@ -1961,8 +1963,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, if (rep == SILFunctionType::Representation::WitnessMethod) { auto protocolName = *attrs.conventionWitnessMethodProtocol; - witnessMethodProtocol = new (TC.Context) SimpleIdentTypeRepr( - SourceLoc(), TC.Context.getIdentifier(protocolName)); + witnessMethodProtocol = new (Context) SimpleIdentTypeRepr( + SourceLoc(), Context.getIdentifier(protocolName)); } } @@ -1986,8 +1988,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, .Case("c", FunctionType::Representation::CFunctionPointer) .Default(None); if (!parsedRep) { - TC.diagnose(attrs.getLoc(TAK_convention), - diag::unsupported_convention, attrs.getConvention()); + diagnose(attrs.getLoc(TAK_convention), + diag::unsupported_convention, attrs.getConvention()); rep = FunctionType::Representation::Swift; } else { rep = *parsedRep; @@ -1996,28 +1998,28 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, // @autoclosure is only valid on parameters. if (!isParam && attrs.has(TAK_autoclosure)) { - TC.diagnose(attrs.getLoc(TAK_autoclosure), - isVariadicFunctionParam - ? diag::attr_not_on_variadic_parameters - : diag::attr_only_on_parameters, "@autoclosure"); + diagnose(attrs.getLoc(TAK_autoclosure), + isVariadicFunctionParam + ? diag::attr_not_on_variadic_parameters + : diag::attr_only_on_parameters, "@autoclosure"); attrs.clearAttribute(TAK_autoclosure); } auto *FuncTyInput = fnRepr->getArgsTypeRepr(); if ((!FuncTyInput || FuncTyInput->getNumElements() != 0) && attrs.has(TAK_autoclosure)) { - TC.diagnose(attrs.getLoc(TAK_autoclosure), - diag::autoclosure_function_input_nonunit); + diagnose(attrs.getLoc(TAK_autoclosure), + diag::autoclosure_function_input_nonunit); attrs.clearAttribute(TAK_autoclosure); } // @noreturn has been replaced with a 'Never' return type. if (attrs.has(TAK_noreturn)) { auto loc = attrs.getLoc(TAK_noreturn); - auto attrRange = getTypeAttrRangeWithAt(TC, loc); + auto attrRange = getTypeAttrRangeWithAt(Context, loc); auto resultRange = fnRepr->getResultTypeRepr()->getSourceRange(); - TC.diagnose(loc, diag::noreturn_not_supported) + diagnose(loc, diag::noreturn_not_supported) .fixItRemove(attrRange) .fixItReplace(resultRange, "Never"); } @@ -2048,14 +2050,14 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, // The attribute is meaningless except on non-variadic parameter types. if (!isParam || options.getBaseContext() == TypeResolverContext::EnumElementDecl) { auto loc = attrs.getLoc(TAK_escaping); - auto attrRange = getTypeAttrRangeWithAt(TC, loc); + auto attrRange = getTypeAttrRangeWithAt(Context, loc); - TC.diagnose(loc, diag::escaping_non_function_parameter) - .fixItRemove(attrRange); + diagnose(loc, diag::escaping_non_function_parameter) + .fixItRemove(attrRange); // Try to find a helpful note based on how the type is being used if (options.is(TypeResolverContext::ImmediateOptionalTypeArgument)) { - TC.diagnose(repr->getLoc(), diag::escaping_optional_type_argument); + diagnose(repr->getLoc(), diag::escaping_optional_type_argument); } } @@ -2076,19 +2078,19 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, if (!attrs.has(i)) continue; - auto diag = TC.diagnose(attrs.getLoc(i), - diag::attribute_requires_function_type, - TypeAttributes::getAttrName(i)); + auto diag = diagnose(attrs.getLoc(i), + diag::attribute_requires_function_type, + TypeAttributes::getAttrName(i)); // If we see @escaping among the attributes on this type, because it isn't // a function type, we'll remove it. if (i == TAK_escaping) { - diag.fixItRemove(getTypeAttrRangeWithAt(TC, + diag.fixItRemove(getTypeAttrRangeWithAt(Context, attrs.getLoc(TAK_escaping))); // Specialize the diagnostic for Optionals. if (ty->getOptionalObjectType()) { diag.flush(); - TC.diagnose(repr->getLoc(), diag::escaping_optional_type_argument); + diagnose(repr->getLoc(), diag::escaping_optional_type_argument); } } attrs.clearAttribute(i); @@ -2103,7 +2105,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, // In SIL, handle @opened (n), which creates an existential archetype. if (attrs.has(TAK_opened)) { if (!ty->isExistentialType()) { - TC.diagnose(attrs.getLoc(TAK_opened), diag::opened_non_protocol, ty); + diagnose(attrs.getLoc(TAK_opened), diag::opened_non_protocol, ty); } else { ty = ArchetypeType::getOpened(ty, attrs.OpenedID); } @@ -2138,14 +2140,14 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, // In SIL *only*, allow @dynamic_self to specify a dynamic Self type. if ((options & TypeResolutionFlags::SILMode) && attrs.has(TAK_dynamic_self)) { - ty = rebuildWithDynamicSelf(TC.Context, ty); + ty = rebuildWithDynamicSelf(Context, ty); attrs.clearAttribute(TAK_dynamic_self); } for (unsigned i = 0; i != TypeAttrKind::TAK_Count; ++i) if (attrs.has((TypeAttrKind)i)) - TC.diagnose(attrs.getLoc((TypeAttrKind)i), - diag::attribute_does_not_apply_to_type); + diagnose(attrs.getLoc((TypeAttrKind)i), + diag::attribute_does_not_apply_to_type); return ty; } @@ -2248,7 +2250,7 @@ Type TypeResolver::resolveASTFunctionType(FunctionTypeRepr *repr, if (const auto Void = dyn_cast(args->getElementType(0))) { if (Void->getIdentifier().str() == "Void") { - TC.diagnose(args->getStartLoc(), diag::paren_void_probably_void) + diagnose(args->getStartLoc(), diag::paren_void_probably_void) .fixItReplace(args->getSourceRange(), "()"); repr->setWarned(); } @@ -2275,8 +2277,8 @@ Type TypeResolver::resolveASTFunctionType(FunctionTypeRepr *repr, auto extInfo2 = extInfo.withRepresentation(AnyFunctionType::Representation::Swift); auto simpleFnTy = FunctionType::get(params, outputTy, extInfo2); - TC.diagnose(repr->getStartLoc(), diag::objc_convention_invalid, - simpleFnTy, strName); + diagnose(repr->getStartLoc(), diag::objc_convention_invalid, + simpleFnTy, strName); } break; @@ -2330,7 +2332,7 @@ Type TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr, auto params = genericSig->getGenericParams(); if (repr->getGenericArguments().size() != genericSig->getGenericParams().size()) { - TC.diagnose(repr->getLoc(), diag::sil_box_arg_mismatch); + diagnose(repr->getLoc(), diag::sil_box_arg_mismatch); return ErrorType::get(Context); } @@ -2395,12 +2397,12 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, auto argsTuple = repr->getArgsTypeRepr(); // SIL functions cannot be variadic. if (argsTuple->hasEllipsis()) { - TC.diagnose(argsTuple->getEllipsisLoc(), diag::sil_function_ellipsis); + diagnose(argsTuple->getEllipsisLoc(), diag::sil_function_ellipsis); } // SIL functions cannot have parameter names. for (auto &element : argsTuple->getElements()) { if (element.UnderscoreLoc.isValid()) - TC.diagnose(element.UnderscoreLoc, diag::sil_function_input_label); + diagnose(element.UnderscoreLoc, diag::sil_function_input_label); } for (auto elt : argsTuple->getElements()) { @@ -2423,8 +2425,8 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, // Diagnose non-coroutines that declare yields. if (coroutineKind == SILCoroutineKind::None && !yields.empty()) { - TC.diagnose(repr->getResultTypeRepr()->getLoc(), - diag::sil_non_coro_yields); + diagnose(repr->getResultTypeRepr()->getLoc(), + diag::sil_non_coro_yields); hasError = true; } } @@ -2529,8 +2531,8 @@ SILParameterInfo TypeResolver::resolveSILParameter( auto checkFor = [&](TypeAttrKind tak, ParameterConvention attrConv) { if (!attrs.has(tak)) return; if (convention != DefaultParameterConvention) { - TC.diagnose(attrs.getLoc(tak), diag::sil_function_repeat_convention, - /*input*/ 0); + diagnose(attrs.getLoc(tak), diag::sil_function_repeat_convention, + /*input*/ 0); hadError = true; } attrs.clearAttribute(tak); @@ -2558,7 +2560,7 @@ SILParameterInfo TypeResolver::resolveSILParameter( // Diagnose types that are illegal in SIL. } else if (!type->isLegalSILType()) { - TC.diagnose(repr->getLoc(), diag::illegal_sil_type, type); + diagnose(repr->getLoc(), diag::illegal_sil_type, type); hadError = true; } @@ -2606,8 +2608,8 @@ bool TypeResolver::resolveSingleSILResult(TypeRepr *repr, auto checkFor = [&](TypeAttrKind tak, ResultConvention attrConv) { if (!attrs.has(tak)) return; if (convention != DefaultResultConvention) { - TC.diagnose(attrs.getLoc(tak), diag::sil_function_repeat_convention, - /*result*/ 1); + diagnose(attrs.getLoc(tak), diag::sil_function_repeat_convention, + /*result*/ 1); hadError = true; } attrs.clearAttribute(tak); @@ -2630,7 +2632,7 @@ bool TypeResolver::resolveSingleSILResult(TypeRepr *repr, // Diagnose types that are illegal in SIL. if (!type->isLegalSILType()) { - TC.diagnose(repr->getStartLoc(), diag::illegal_sil_type, type); + diagnose(repr->getStartLoc(), diag::illegal_sil_type, type); return false; } @@ -2648,8 +2650,8 @@ bool TypeResolver::resolveSingleSILResult(TypeRepr *repr, // We don't expect to have a reason to support multiple independent // error results. (Would this be disjunctive or conjunctive?) if (errorResult.hasValue()) { - TC.diagnose(repr->getStartLoc(), - diag::sil_function_multiple_error_results); + diagnose(repr->getStartLoc(), + diag::sil_function_multiple_error_results); return true; } @@ -2666,7 +2668,7 @@ bool TypeResolver::resolveSILResults(TypeRepr *repr, bool hadError = false; for (auto &element : tuple->getElements()) { if (element.UnderscoreLoc.isValid()) - TC.diagnose(element.UnderscoreLoc, diag::sil_function_output_label); + diagnose(element.UnderscoreLoc, diag::sil_function_output_label); } for (auto elt : tuple->getElements()) { if (resolveSingleSILResult(elt.Type, options, @@ -2710,7 +2712,7 @@ Type TypeResolver::resolveSpecifierTypeRepr(SpecifierTypeRepr *repr, default: llvm_unreachable("unknown SpecifierTypeRepr kind"); } - TC.diagnose(repr->getSpecifierLoc(), diagID, name); + diagnose(repr->getSpecifierLoc(), diagID, name); repr->setInvalid(); return ErrorType::get(Context); } @@ -2749,7 +2751,7 @@ Type TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr, Type valueTy = resolveType(repr->getValue(), options.withoutContext()); if (!valueTy || valueTy->hasError()) return valueTy; - auto dictDecl = TC.Context.getDictionaryDecl(); + auto dictDecl = Context.getDictionaryDecl(); if (auto dictTy = TC.getDictionaryType(repr->getBrackets().Start, keyTy, valueTy)) { @@ -2830,16 +2832,16 @@ Type TypeResolver::resolveImplicitlyUnwrappedOptionalType( if (doDiag) { // Prior to Swift 5, we allow 'as T!' and turn it into a disjunction. - if (TC.Context.isSwiftVersionAtLeast(5)) { - TC.diagnose(repr->getStartLoc(), - diag::implicitly_unwrapped_optional_in_illegal_position) + if (Context.isSwiftVersionAtLeast(5)) { + diagnose(repr->getStartLoc(), + diag::implicitly_unwrapped_optional_in_illegal_position) .fixItReplace(repr->getExclamationLoc(), "?"); } else if (options.is(TypeResolverContext::ExplicitCastExpr)) { - TC.diagnose( + diagnose( repr->getStartLoc(), diag::implicitly_unwrapped_optional_deprecated_in_this_position); } else { - TC.diagnose( + diagnose( repr->getStartLoc(), diag::implicitly_unwrapped_optional_in_illegal_position_interpreted_as_optional) .fixItReplace(repr->getExclamationLoc(), "?"); @@ -2876,7 +2878,7 @@ Type TypeResolver::resolveTupleType(TupleTypeRepr *repr, // Variadic tuples are not permitted. bool complained = false; if (repr->hasEllipsis()) { - TC.diagnose(repr->getEllipsisLoc(), diag::tuple_ellipsis); + diagnose(repr->getEllipsisLoc(), diag::tuple_ellipsis); repr->removeEllipsis(); complained = true; } @@ -2895,8 +2897,7 @@ Type TypeResolver::resolveTupleType(TupleTypeRepr *repr, if (elements.size() == 1 && elements[0].hasName() && !(options & TypeResolutionFlags::SILType)) { if (!complained) { - TC.diagnose(repr->getElementNameLoc(0), - diag::tuple_single_element) + diagnose(repr->getElementNameLoc(0), diag::tuple_single_element) .fixItRemoveChars(repr->getElementNameLoc(0), repr->getElementType(0)->getStartLoc()); } @@ -2924,8 +2925,8 @@ Type TypeResolver::resolveCompositionType(CompositionTypeRepr *repr, auto checkSuperclass = [&](SourceLoc loc, Type t) -> bool { if (SuperclassType && !SuperclassType->isEqual(t)) { - TC.diagnose(loc, diag::protocol_composition_one_class, t, - SuperclassType); + diagnose(loc, diag::protocol_composition_one_class, t, + SuperclassType); return true; } @@ -2958,9 +2959,9 @@ Type TypeResolver::resolveCompositionType(CompositionTypeRepr *repr, continue; } - TC.diagnose(tyR->getStartLoc(), - diag::invalid_protocol_composition_member, - ty); + diagnose(tyR->getStartLoc(), + diag::invalid_protocol_composition_member, + ty); } // Avoid confusing diagnostics ('MyClass' not convertible to 'MyClass', @@ -2987,7 +2988,7 @@ Type TypeResolver::resolveMetatypeType(MetatypeTypeRepr *repr, // @objc_metatype attribute, so metatypes should have been lowered // in resolveAttributedType. if (options & TypeResolutionFlags::SILType) { - TC.diagnose(repr->getStartLoc(), diag::sil_metatype_without_repr); + diagnose(repr->getStartLoc(), diag::sil_metatype_without_repr); storedRepr = MetatypeRepresentation::Thick; } @@ -3018,7 +3019,7 @@ Type TypeResolver::resolveProtocolType(ProtocolTypeRepr *repr, // @objc_metatype attribute, so metatypes should have been lowered // in resolveAttributedType. if (options & TypeResolutionFlags::SILType) { - TC.diagnose(repr->getStartLoc(), diag::sil_metatype_without_repr); + diagnose(repr->getStartLoc(), diag::sil_metatype_without_repr); storedRepr = MetatypeRepresentation::Thick; } @@ -3030,9 +3031,9 @@ Type TypeResolver::buildProtocolType( Type instanceType, Optional storedRepr) { if (!instanceType->isAnyExistentialType()) { - TC.diagnose(repr->getProtocolLoc(), diag::dot_protocol_on_non_existential, - instanceType); - return ErrorType::get(TC.Context); + diagnose(repr->getProtocolLoc(), diag::dot_protocol_on_non_existential, + instanceType); + return ErrorType::get(Context); } return MetatypeType::get(instanceType, storedRepr); From 2615070d1856d0166fdecaf8674d36eb8f34c5d1 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 20 Aug 2018 17:21:15 -0700 Subject: [PATCH 2/7] [Type checker] Detangle get(Array|Dictionary|Optional)Type from TypeChecker. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They’re still static methods for convenience, but they don’t depend on the type checker’s state. --- lib/Sema/TypeCheckType.cpp | 30 ++++++++++++++++++------------ lib/Sema/TypeChecker.h | 6 +++--- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 9b547f7d295ba..3fa5d9ab857fc 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -291,8 +291,9 @@ bool TypeResolution::areSameType(Type type1, Type type2) const { } Type TypeChecker::getArraySliceType(SourceLoc loc, Type elementType) { - if (!Context.getArrayDecl()) { - diagnose(loc, diag::sugar_type_not_found, 0); + ASTContext &ctx = elementType->getASTContext(); + if (!ctx.getArrayDecl()) { + ctx.Diags.diagnose(loc, diag::sugar_type_not_found, 0); return Type(); } @@ -301,17 +302,19 @@ Type TypeChecker::getArraySliceType(SourceLoc loc, Type elementType) { Type TypeChecker::getDictionaryType(SourceLoc loc, Type keyType, Type valueType) { - if (!Context.getDictionaryDecl()) { - diagnose(loc, diag::sugar_type_not_found, 3); + ASTContext &ctx = keyType->getASTContext(); + if (!ctx.getDictionaryDecl()) { + ctx.Diags.diagnose(loc, diag::sugar_type_not_found, 3); return Type(); } - return DictionaryType::get(keyType, valueType); + return DictionaryType::get(keyType, valueType); } Type TypeChecker::getOptionalType(SourceLoc loc, Type elementType) { - if (!Context.getOptionalDecl()) { - diagnose(loc, diag::sugar_type_not_found, 1); + ASTContext &ctx = elementType->getASTContext(); + if (!ctx.getOptionalDecl()) { + ctx.Diags.diagnose(loc, diag::sugar_type_not_found, 1); return Type(); } @@ -2731,7 +2734,8 @@ Type TypeResolver::resolveArrayType(ArrayTypeRepr *repr, Type baseTy = resolveType(repr->getBase(), options.withoutContext()); if (!baseTy || baseTy->hasError()) return baseTy; - auto sliceTy = TC.getArraySliceType(repr->getBrackets().Start, baseTy); + auto sliceTy = + TypeChecker::getArraySliceType(repr->getBrackets().Start, baseTy); if (!sliceTy) return ErrorType::get(Context); @@ -2753,8 +2757,8 @@ Type TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr, auto dictDecl = Context.getDictionaryDecl(); - if (auto dictTy = TC.getDictionaryType(repr->getBrackets().Start, keyTy, - valueTy)) { + if (auto dictTy = TypeChecker::getDictionaryType(repr->getBrackets().Start, + keyTy, valueTy)) { // Check the requirements on the generic arguments. TC.validateDecl(dictDecl); auto unboundTy = dictDecl->getDeclaredType()->castTo(); @@ -2787,7 +2791,8 @@ Type TypeResolver::resolveOptionalType(OptionalTypeRepr *repr, Type baseTy = resolveType(repr->getBase(), elementOptions); if (!baseTy || baseTy->hasError()) return baseTy; - auto optionalTy = TC.getOptionalType(repr->getQuestionLoc(), baseTy); + auto optionalTy = TypeChecker::getOptionalType(repr->getQuestionLoc(), + baseTy); if (!optionalTy) return ErrorType::get(Context); return optionalTy; @@ -2857,7 +2862,8 @@ Type TypeResolver::resolveImplicitlyUnwrappedOptionalType( if (!baseTy || baseTy->hasError()) return baseTy; Type uncheckedOptionalTy; - uncheckedOptionalTy = TC.getOptionalType(repr->getExclamationLoc(), baseTy); + uncheckedOptionalTy = TypeChecker::getOptionalType(repr->getExclamationLoc(), + baseTy); if (!uncheckedOptionalTy) return ErrorType::get(Context); diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 2810ef00dab71..260d8b2e95fdf 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1047,9 +1047,9 @@ class TypeChecker final : public LazyResolver { return Diags.diagnose(std::forward(Args)...); } - Type getArraySliceType(SourceLoc loc, Type elementType); - Type getDictionaryType(SourceLoc loc, Type keyType, Type valueType); - Type getOptionalType(SourceLoc loc, Type elementType); + static Type getArraySliceType(SourceLoc loc, Type elementType); + static Type getDictionaryType(SourceLoc loc, Type keyType, Type valueType); + static Type getOptionalType(SourceLoc loc, Type elementType); Type getUnsafePointerType(SourceLoc loc, Type pointeeType); Type getUnsafeMutablePointerType(SourceLoc loc, Type pointeeType); Type getStringType(DeclContext *dc); From 05b103598f963493d02770cdcd9a6cd6f14ecb2a Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 20 Aug 2018 20:43:51 -0700 Subject: [PATCH 3/7] [Type checker] Start removing TypeChecker dependencies from type resolution. --- lib/Sema/TypeCheckType.cpp | 26 ++++++++++++++------------ lib/Sema/TypeCheckType.h | 3 +++ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 3fa5d9ab857fc..28e7d2184572d 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1137,7 +1137,9 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, ComponentIdentTypeRepr *comp, TypeResolutionOptions options) { // Short-circuiting. - if (comp->isInvalid()) return ErrorType::get(TC.Context); + ASTContext &ctx = resolution.getASTContext(); + auto &diags = ctx.Diags; + if (comp->isInvalid()) return ErrorType::get(ctx); // If the component has already been bound to a declaration, handle // that now. @@ -1155,7 +1157,7 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, // Dynamic 'Self' in the result type of a function body. if (options.getBaseContext() == TypeResolverContext::DynamicSelfResult && - comp->getIdentifier() == TC.Context.Id_Self) { + comp->getIdentifier() == ctx.Id_Self) { auto func = cast(DC); assert(func->hasDynamicSelf() && "Not marked as having dynamic Self?"); @@ -1165,7 +1167,7 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, auto selfType = resolution.mapTypeIntoContext( func->getDeclContext()->getSelfInterfaceType()); - return DynamicSelfType::get(selfType, TC.Context); + return DynamicSelfType::get(selfType, ctx); } auto id = comp->getIdentifier(); @@ -1173,10 +1175,10 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, NameLookupOptions lookupOptions = defaultUnqualifiedLookupOptions; if (options.contains(TypeResolutionFlags::KnownNonCascadingDependency)) lookupOptions |= NameLookupFlags::KnownPrivate; - auto globals = TC.lookupUnqualifiedType(lookupDC, - id, - comp->getIdLoc(), - lookupOptions); + auto globals = TypeChecker::lookupUnqualifiedType(lookupDC, + id, + comp->getIdLoc(), + lookupOptions); // Process the names we found. Type current; @@ -1219,16 +1221,16 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, // FIXME: We could recover by looking at later components. if (isAmbiguous) { if (!options.contains(TypeResolutionFlags::SilenceErrors)) { - TC.diagnose(comp->getIdLoc(), diag::ambiguous_type_base, - comp->getIdentifier()) + diags.diagnose(comp->getIdLoc(), diag::ambiguous_type_base, + comp->getIdentifier()) .highlight(comp->getIdLoc()); for (auto entry : globals) { - TC.diagnose(entry.getValueDecl(), diag::found_candidate); + entry.getValueDecl()->diagnose(diag::found_candidate); } } comp->setInvalid(); - return ErrorType::get(TC.Context); + return ErrorType::get(ctx); } // If we found nothing, complain and give ourselves a chance to recover. @@ -1236,7 +1238,7 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, // If we're not allowed to complain or we couldn't fix the // source, bail out. if (options.contains(TypeResolutionFlags::SilenceErrors)) - return ErrorType::get(TC.Context); + return ErrorType::get(ctx); return diagnoseUnknownType(TC, resolution, nullptr, SourceRange(), comp, options, lookupOptions); diff --git a/lib/Sema/TypeCheckType.h b/lib/Sema/TypeCheckType.h index 67050985c95fa..3ebcd18c4cb92 100644 --- a/lib/Sema/TypeCheckType.h +++ b/lib/Sema/TypeCheckType.h @@ -67,6 +67,9 @@ class TypeResolution { static TypeResolution forContextual(DeclContext *dc, GenericEnvironment *genericEnv); + /// Retrieve the ASTContext in which this resolution occurs. + ASTContext &getASTContext() const { return dc->getASTContext(); } + /// Retrieve the declaration context in which type resolution will be /// performed. DeclContext *getDeclContext() const { return dc; } From 27563773670f50b3e076d5f624a0ad50875ed0e7 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 20 Aug 2018 21:39:44 -0700 Subject: [PATCH 4/7] [Type checker] Separate more functionality from the TypeChecker instance. Use the usual bag of tricks to eliminating dependence on the TypeChecker instance: static functions, LazyResolver callbacks, and emitting diagnostics on decls/ASTContext. --- lib/Sema/ConstraintSystem.cpp | 9 +- .../DerivedConformanceEquatableHashable.cpp | 34 ++-- lib/Sema/DerivedConformances.cpp | 10 +- lib/Sema/DerivedConformances.h | 7 +- lib/Sema/TypeCheckGeneric.cpp | 7 +- lib/Sema/TypeCheckNameLookup.cpp | 14 +- lib/Sema/TypeCheckProtocol.cpp | 29 +-- lib/Sema/TypeCheckProtocolInference.cpp | 4 +- lib/Sema/TypeCheckType.cpp | 183 ++++++++++-------- lib/Sema/TypeChecker.h | 49 +++-- 10 files changed, 181 insertions(+), 165 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 1a8c95053f148..17013cb4f4d5c 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -980,10 +980,11 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, // Unqualified reference to a type. if (auto typeDecl = dyn_cast(value)) { // Resolve the reference to this type declaration in our current context. - auto type = TC.resolveTypeInContext(typeDecl, nullptr, - TypeResolution::forContextual(useDC), - TypeResolverContext::InExpression, - /*isSpecialized=*/false); + auto type = TypeChecker::resolveTypeInContext( + typeDecl, nullptr, + TypeResolution::forContextual(useDC), + TypeResolverContext::InExpression, + /*isSpecialized=*/false); // Open the type. type = openUnboundGenericType(type, locator); diff --git a/lib/Sema/DerivedConformanceEquatableHashable.cpp b/lib/Sema/DerivedConformanceEquatableHashable.cpp index a52ec0eff479c..fa3b4a2595fec 100644 --- a/lib/Sema/DerivedConformanceEquatableHashable.cpp +++ b/lib/Sema/DerivedConformanceEquatableHashable.cpp @@ -37,13 +37,13 @@ using namespace swift; /// \p theEnum The enum whose elements and associated values should be checked. /// \p protocol The protocol being requested. /// \return True if all associated values of all elements of the enum conform. -static bool allAssociatedValuesConformToProtocol(TypeChecker &tc, - DeclContext *DC, +static bool allAssociatedValuesConformToProtocol(DeclContext *DC, EnumDecl *theEnum, ProtocolDecl *protocol) { + auto lazyResolver = DC->getASTContext().getLazyResolver(); for (auto elt : theEnum->getAllElements()) { if (!elt->hasInterfaceType()) - tc.validateDecl(elt); + lazyResolver->resolveDeclSignature(elt); auto PL = elt->getParameterList(); if (!PL) @@ -51,8 +51,9 @@ static bool allAssociatedValuesConformToProtocol(TypeChecker &tc, for (auto param : *PL) { auto type = param->getType()->mapTypeOutOfContext(); - if (!tc.conformsToProtocol(DC->mapTypeIntoContext(type), protocol, DC, - ConformanceCheckFlags::Used)) { + if (!TypeChecker::conformsToProtocol(DC->mapTypeIntoContext(type), + protocol, DC, + ConformanceCheckFlags::Used)) { return false; } } @@ -65,21 +66,22 @@ static bool allAssociatedValuesConformToProtocol(TypeChecker &tc, /// \p theStruct The struct whose stored properties should be checked. /// \p protocol The protocol being requested. /// \return True if all stored properties of the struct conform. -static bool allStoredPropertiesConformToProtocol(TypeChecker &tc, - DeclContext *DC, +static bool allStoredPropertiesConformToProtocol(DeclContext *DC, StructDecl *theStruct, ProtocolDecl *protocol) { + auto lazyResolver = DC->getASTContext().getLazyResolver(); auto storedProperties = theStruct->getStoredProperties(/*skipInaccessible=*/true); for (auto propertyDecl : storedProperties) { if (!propertyDecl->hasType()) - tc.validateDecl(propertyDecl); + lazyResolver->resolveDeclSignature(propertyDecl); if (!propertyDecl->hasType()) return false; auto type = propertyDecl->getType()->mapTypeOutOfContext(); - if (!tc.conformsToProtocol(DC->mapTypeIntoContext(type), protocol, DC, - ConformanceCheckFlags::Used)) { + if (!TypeChecker::conformsToProtocol(DC->mapTypeIntoContext(type), + protocol, DC, + ConformanceCheckFlags::Used)) { return false; } } @@ -87,19 +89,19 @@ static bool allStoredPropertiesConformToProtocol(TypeChecker &tc, } /// Common preconditions for Equatable and Hashable. -static bool canDeriveConformance(TypeChecker &tc, DeclContext *DC, +static bool canDeriveConformance(DeclContext *DC, NominalTypeDecl *target, ProtocolDecl *protocol) { // The type must be an enum or a struct. if (auto enumDecl = dyn_cast(target)) { // The cases must not have associated values, or all associated values must // conform to the protocol. - return allAssociatedValuesConformToProtocol(tc, DC, enumDecl, protocol); + return allAssociatedValuesConformToProtocol(DC, enumDecl, protocol); } if (auto structDecl = dyn_cast(target)) { // All stored properties of the struct must conform to the protocol. - return allStoredPropertiesConformToProtocol(tc, DC, structDecl, protocol); + return allStoredPropertiesConformToProtocol(DC, structDecl, protocol); } return false; @@ -675,12 +677,12 @@ deriveEquatable_eq(DerivedConformance &derived, return eqDecl; } -bool DerivedConformance::canDeriveEquatable(TypeChecker &tc, DeclContext *DC, +bool DerivedConformance::canDeriveEquatable(DeclContext *DC, NominalTypeDecl *type) { ASTContext &ctx = DC->getASTContext(); auto equatableProto = ctx.getProtocol(KnownProtocolKind::Equatable); if (!equatableProto) return false; - return canDeriveConformance(tc, DC, type, equatableProto); + return canDeriveConformance(DC, type, equatableProto); } ValueDecl *DerivedConformance::deriveEquatable(ValueDecl *requirement) { @@ -1187,7 +1189,7 @@ ValueDecl *DerivedConformance::deriveHashable(ValueDecl *requirement) { // Refuse to synthesize Hashable if type isn't a struct or enum, or if it // has non-Hashable stored properties/associated values. auto hashableProto = C.getProtocol(KnownProtocolKind::Hashable); - if (!canDeriveConformance(TC, getConformanceContext(), Nominal, + if (!canDeriveConformance(getConformanceContext(), Nominal, hashableProto)) { TC.diagnose(ConformanceDecl->getLoc(), diag::type_does_not_conform, Nominal->getDeclaredType(), diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index 21b612b74c8a4..110f380ccd335 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -47,8 +47,7 @@ Type DerivedConformance::getProtocolType() const { return Protocol->getDeclaredType(); } -bool DerivedConformance::derivesProtocolConformance(TypeChecker &TC, - DeclContext *DC, +bool DerivedConformance::derivesProtocolConformance(DeclContext *DC, NominalTypeDecl *Nominal, ProtocolDecl *Protocol) { // Only known protocols can be derived. @@ -73,7 +72,7 @@ bool DerivedConformance::derivesProtocolConformance(TypeChecker &TC, // Enums without associated values can implicitly derive Equatable // conformance. case KnownProtocolKind::Equatable: - return canDeriveEquatable(TC, DC, Nominal); + return canDeriveEquatable(DC, Nominal); // "Simple" enums without availability attributes can explicitly derive // a CaseIterable conformance. @@ -129,7 +128,7 @@ bool DerivedConformance::derivesProtocolConformance(TypeChecker &TC, if (auto structDecl = dyn_cast(Nominal)) { switch (*knownProtocol) { case KnownProtocolKind::Equatable: - return canDeriveEquatable(TC, DC, Nominal); + return canDeriveEquatable(DC, Nominal); default: return false; } @@ -158,8 +157,7 @@ ValueDecl *DerivedConformance::getDerivableRequirement(TypeChecker &tc, ConformanceCheckFlags::SkipConditionalRequirements)) { auto DC = conformance->getConcrete()->getDeclContext(); // Check whether this nominal type derives conformances to the protocol. - if (!DerivedConformance::derivesProtocolConformance(tc, DC, nominal, - proto)) + if (!DerivedConformance::derivesProtocolConformance(DC, nominal, proto)) return nullptr; } diff --git a/lib/Sema/DerivedConformances.h b/lib/Sema/DerivedConformances.h index 03bc347b954cf..33fa195cbc05b 100644 --- a/lib/Sema/DerivedConformances.h +++ b/lib/Sema/DerivedConformances.h @@ -58,8 +58,6 @@ class DerivedConformance { /// declarations for requirements of the protocol that are not satisfied by /// the type's explicit members. /// - /// \param tc The type checker. - /// /// \param nominal The nominal type for which we are determining whether to /// derive a witness. /// @@ -67,7 +65,7 @@ class DerivedConformance { /// /// \return True if the type can implicitly derive a conformance for the /// given protocol. - static bool derivesProtocolConformance(TypeChecker &tc, DeclContext *DC, + static bool derivesProtocolConformance(DeclContext *DC, NominalTypeDecl *nominal, ProtocolDecl *protocol); @@ -120,8 +118,7 @@ class DerivedConformance { /// associated values, and for structs with all-Equatable stored properties. /// /// \returns True if the requirement can be derived. - static bool canDeriveEquatable(TypeChecker &tc, DeclContext *DC, - NominalTypeDecl *type); + static bool canDeriveEquatable(DeclContext *DC, NominalTypeDecl *type); /// Derive an Equatable requirement for a type. /// diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 5e0fc2db6e551..a58b8066f48a3 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -1068,14 +1068,17 @@ RequirementCheckResult TypeChecker::checkGenericArguments( } break; - case RequirementKind::Superclass: + case RequirementKind::Superclass: { // Superclass requirements. - if (!isSubclassOf(firstType, secondType, dc)) { + // FIXME: Don't use the type checker instance here? + TypeChecker &tc = static_cast(*ctx.getLazyResolver()); + if (!tc.isSubclassOf(firstType, secondType, dc)) { diagnostic = diag::type_does_not_inherit; diagnosticNote = diag::type_does_not_inherit_or_conform_requirement; requirementFailure = true; } break; + } case RequirementKind::SameType: if (!firstType->isEqual(secondType)) { diff --git a/lib/Sema/TypeCheckNameLookup.cpp b/lib/Sema/TypeCheckNameLookup.cpp index b8b335ddf5919..656deb9448a0b 100644 --- a/lib/Sema/TypeCheckNameLookup.cpp +++ b/lib/Sema/TypeCheckNameLookup.cpp @@ -447,7 +447,7 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, if (options.contains(NameLookupFlags::IgnoreAccessControl)) subOptions |= NL_IgnoreAccessControl; - if (!dc->lookupQualified(type, name, subOptions, this, decls)) + if (!dc->lookupQualified(type, name, subOptions, nullptr, decls)) return result; // Look through the declarations, keeping only the unique type declarations. @@ -457,9 +457,11 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, auto *typeDecl = cast(decl); // FIXME: This should happen before we attempt shadowing checks. - validateDecl(typeDecl); - if (!typeDecl->hasInterfaceType()) // FIXME: recursion-breaking hack - continue; + if (!typeDecl->hasInterfaceType()) { + dc->getASTContext().getLazyResolver()->resolveDeclSignature(typeDecl); + if (!typeDecl->hasInterfaceType()) // FIXME: recursion-breaking hack + continue; + } auto memberType = typeDecl->getDeclaredInterfaceType(); @@ -548,7 +550,9 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc, ProtocolConformanceState::CheckingTypeWitnesses) continue; - auto typeDecl = concrete->getTypeWitnessAndDecl(assocType, this).second; + auto lazyResolver = dc->getASTContext().getLazyResolver(); + auto typeDecl = + concrete->getTypeWitnessAndDecl(assocType, lazyResolver).second; assert(typeDecl && "Missing type witness?"); diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index aa9468475f9c5..38986f2e6eede 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -3042,7 +3042,7 @@ ResolveWitnessResult ConformanceChecker::resolveWitnessViaDerivation( // Find the declaration that derives the protocol conformance. NominalTypeDecl *derivingTypeDecl = nullptr; auto *nominal = Adoptee->getAnyNominal(); - if (DerivedConformance::derivesProtocolConformance(TC, DC, nominal, Proto)) + if (DerivedConformance::derivesProtocolConformance(DC, nominal, Proto)) derivingTypeDecl = nominal; if (!derivingTypeDecl) { @@ -3386,7 +3386,7 @@ void ConformanceChecker::ensureRequirementsAreSatisfied( { Type(proto->getProtocolSelfType()) }, proto->getRequirementSignature(), QuerySubstitutionMap{substitutions}, - TypeChecker::LookUpConformance(TC, DC), + TypeChecker::LookUpConformance(DC), ConformanceCheckFlags::Used, &listener); switch (result) { @@ -3692,7 +3692,7 @@ void ConformanceChecker::checkConformance(MissingWitnessDiagnosisKind Kind) { } } -static void diagnoseConformanceFailure(TypeChecker &TC, Type T, +static void diagnoseConformanceFailure(Type T, ProtocolDecl *Proto, DeclContext *DC, SourceLoc ComplainLoc) { @@ -3705,7 +3705,7 @@ static void diagnoseConformanceFailure(TypeChecker &TC, Type T, // If we're checking conformance of an existential type to a protocol, // do a little bit of extra work to produce a better diagnostic. if (T->isExistentialType() && - TC.containsProtocol(T, Proto, DC, None)) { + TypeChecker::containsProtocol(T, Proto, DC, None)) { if (!T->isObjCExistentialType()) { diags.diagnose(ComplainLoc, diag::protocol_does_not_conform_objc, @@ -3729,7 +3729,7 @@ static void diagnoseConformanceFailure(TypeChecker &TC, Type T, // conformance to RawRepresentable was inferred. if (auto enumDecl = T->getEnumOrBoundGenericEnum()) { if (Proto->isSpecificProtocol(KnownProtocolKind::RawRepresentable) && - DerivedConformance::derivesProtocolConformance(TC, DC, enumDecl, + DerivedConformance::derivesProtocolConformance(DC, enumDecl, Proto) && enumDecl->hasRawType() && !enumDecl->getRawType()->is()) { @@ -3746,7 +3746,8 @@ static void diagnoseConformanceFailure(TypeChecker &TC, Type T, if (!equatableProto) return; - if (!TC.conformsToProtocol(rawType, equatableProto, enumDecl, None)) { + if (!TypeChecker::conformsToProtocol(rawType, equatableProto, enumDecl, + None)) { SourceLoc loc = enumDecl->getInherited()[0].getSourceRange().Start; diags.diagnose(loc, diag::enum_raw_type_not_equatable, rawType); return; @@ -3780,7 +3781,7 @@ void ConformanceChecker::diagnoseOrDefer( // Complain that the type does not conform, once. if (isError && !AlreadyComplained) { - diagnoseConformanceFailure(TC, Adoptee, Proto, DC, Loc); + diagnoseConformanceFailure(Adoptee, Proto, DC, Loc); AlreadyComplained = true; } @@ -3865,7 +3866,7 @@ Optional TypeChecker::conformsToProtocol( auto lookupResult = M->lookupConformance(T, Proto); if (!lookupResult) { if (ComplainLoc.isValid()) - diagnoseConformanceFailure(*this, T, Proto, DC, ComplainLoc); + diagnoseConformanceFailure(T, Proto, DC, ComplainLoc); else recordDependency(); @@ -3881,7 +3882,8 @@ Optional TypeChecker::conformsToProtocol( // If we're using this conformance, note that. if (options.contains(ConformanceCheckFlags::Used)) { - markConformanceUsed(*lookupResult, DC); + if (auto lazyResolver = DC->getASTContext().getLazyResolver()) + lazyResolver->markConformanceUsed(*lookupResult, DC); } auto condReqs = lookupResult->getConditionalRequirementsIfAvailable(); @@ -3909,7 +3911,7 @@ Optional TypeChecker::conformsToProtocol( {Type(lookupResult->getRequirement()->getProtocolSelfType())}, *condReqs, [](SubstitutableType *dependentType) { return Type(dependentType); }, - LookUpConformance(*this, DC), options); + LookUpConformance(DC), options); switch (conditionalCheckResult) { case RequirementCheckResult::Success: break; @@ -3922,7 +3924,8 @@ Optional TypeChecker::conformsToProtocol( // When requested, print the conformance access path used to find this // conformance. - if (Context.LangOpts.DebugGenericSignatures && + ASTContext &ctx = Proto->getASTContext(); + if (ctx.LangOpts.DebugGenericSignatures && InExpression && T->is() && lookupResult->isAbstract() && !T->castTo()->isOpenedExistential() && !T->castTo()->requiresClass() && @@ -3972,7 +3975,7 @@ TypeChecker::LookUpConformance::operator()( if (conformingReplacementType->isTypeParameter()) return ProtocolConformanceRef(conformedProtocol); - return tc.conformsToProtocol( + return TypeChecker::conformsToProtocol( conformingReplacementType, conformedProtocol, dc, @@ -4780,7 +4783,7 @@ void TypeChecker::checkConformancesInContext(DeclContext *dc, if (auto enumDecl = dyn_cast(existingDecl)) { if (diag.Protocol->isSpecificProtocol( KnownProtocolKind::RawRepresentable) && - DerivedConformance::derivesProtocolConformance(*this, dc, enumDecl, + DerivedConformance::derivesProtocolConformance(dc, enumDecl, diag.Protocol) && enumDecl->hasRawType() && enumDecl->getInherited()[0].getSourceRange().isValid()) { diff --git a/lib/Sema/TypeCheckProtocolInference.cpp b/lib/Sema/TypeCheckProtocolInference.cpp index aff9f2a3ce345..fc1c2aa8cd073 100644 --- a/lib/Sema/TypeCheckProtocolInference.cpp +++ b/lib/Sema/TypeCheckProtocolInference.cpp @@ -886,7 +886,7 @@ Type AssociatedTypeInference::computeDerivedTypeWitness( // Can we derive conformances for this protocol and adoptee? NominalTypeDecl *derivingTypeDecl = adoptee->getAnyNominal(); - if (!DerivedConformance::derivesProtocolConformance(tc, dc, derivingTypeDecl, + if (!DerivedConformance::derivesProtocolConformance(dc, derivingTypeDecl, proto)) return Type(); @@ -1117,7 +1117,7 @@ bool AssociatedTypeInference::checkCurrentTypeWitnesses( { Type(proto->getProtocolSelfType()) }, sanitizedRequirements, QuerySubstitutionMap{substitutions}, - TypeChecker::LookUpConformance(tc, dc), + TypeChecker::LookUpConformance(dc), None, nullptr, options); switch (result) { case RequirementCheckResult::Failure: diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 28e7d2184572d..61b39f75a6ec1 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -451,6 +451,7 @@ Type TypeChecker::resolveTypeInContext( bool isSpecialized) { auto fromDC = resolution.getDeclContext(); + ASTContext &ctx = fromDC->getASTContext(); // If we found a generic parameter, map to the archetype if there is one. if (auto genericParam = dyn_cast(typeDecl)) { @@ -521,7 +522,7 @@ Type TypeChecker::resolveTypeInContext( // protocol extension, always use the nominal type and // not the protocol 'Self' type. if (!foundDC->getDeclaredInterfaceType()) - return ErrorType::get(Context); + return ErrorType::get(ctx); selfType = resolution.mapTypeIntoContext( foundDC->getDeclaredInterfaceType()); @@ -539,10 +540,10 @@ Type TypeChecker::resolveTypeInContext( // Get the superclass of the 'Self' type parameter. auto *sig = foundDC->getGenericSignatureOfContext(); if (!sig) - return ErrorType::get(Context); + return ErrorType::get(ctx); auto superclassType = sig->getSuperclassBound(selfType); if (!superclassType) - return ErrorType::get(Context); + return ErrorType::get(ctx); selfType = superclassType; } @@ -591,11 +592,13 @@ Type TypeChecker::applyGenericArguments(Type type, } auto dc = resolution.getDeclContext(); + auto &ctx = dc->getASTContext(); + auto &diags = ctx.Diags; // We must either have an unbound generic type, or a generic type alias. if (!type->is()) { if (!options.contains(TypeResolutionFlags::SilenceErrors)) { - auto diag = diagnose(loc, diag::not_a_generic_type, type); + auto diag = diags.diagnose(loc, diag::not_a_generic_type, type); // Don't add fixit on module type; that isn't the right type regardless // of whether it had generic arguments. @@ -623,14 +626,14 @@ Type TypeChecker::applyGenericArguments(Type type, auto genericParams = genericDecl->getGenericParams(); if (genericParams->size() != genericArgs.size()) { if (!options.contains(TypeResolutionFlags::SilenceErrors)) { - diagnose(loc, diag::type_parameter_count_mismatch, decl->getName(), - genericParams->size(), genericArgs.size(), - genericArgs.size() < genericParams->size()) + diags.diagnose(loc, diag::type_parameter_count_mismatch, decl->getName(), + genericParams->size(), genericArgs.size(), + genericArgs.size() < genericParams->size()) .highlight(generic->getAngleBrackets()); diagnose(decl, diag::kind_identifier_declared_here, DescriptiveDeclKind::GenericType, decl->getName()); } - return ErrorType::get(Context); + return ErrorType::get(ctx); } // In SIL mode, Optional interprets T as a SIL type. @@ -654,20 +657,19 @@ Type TypeChecker::applyGenericArguments(Type type, // Cannot extend a bound generic type. if (options.is(TypeResolverContext::ExtensionBinding)) { if (!options.contains(TypeResolutionFlags::SilenceErrors)) { - diagnose(loc, diag::extension_specialization, + diags.diagnose(loc, diag::extension_specialization, genericDecl->getName()) .highlight(generic->getSourceRange()); } - return ErrorType::get(Context); + return ErrorType::get(ctx); } // FIXME: More principled handling of circularity. if (!genericDecl->hasValidSignature()) { - diagnose(loc, diag::recursive_type_reference, + diags.diagnose(loc, diag::recursive_type_reference, genericDecl->getDescriptiveKind(), genericDecl->getName()); - diagnose(genericDecl, diag::kind_declared_here, - DescriptiveDeclKind::Type); - return ErrorType::get(Context); + genericDecl->diagnose(diag::kind_declared_here, DescriptiveDeclKind::Type); + return ErrorType::get(ctx); } // Resolve the types of the generic arguments. @@ -678,7 +680,7 @@ Type TypeChecker::applyGenericArguments(Type type, // Propagate failure. TypeLoc genericArg = tyR; if (validateType(genericArg, resolution, options)) - return ErrorType::get(Context); + return ErrorType::get(ctx); auto substTy = genericArg.getType(); @@ -698,10 +700,10 @@ Type TypeChecker::applyGenericArguments(Type type, bool isMutablePointer; if (isPointerToVoid(dc->getASTContext(), result, isMutablePointer)) { if (isMutablePointer) - diagnose(loc, diag::use_of_void_pointer, "Mutable"). + diags.diagnose(loc, diag::use_of_void_pointer, "Mutable"). fixItReplace(generic->getSourceRange(), "UnsafeMutableRawPointer"); else - diagnose(loc, diag::use_of_void_pointer, ""). + diags.diagnose(loc, diag::use_of_void_pointer, ""). fixItReplace(generic->getSourceRange(), "UnsafeRawPointer"); } return result; @@ -771,7 +773,7 @@ Type TypeChecker::applyUnboundGenericArguments( genericSig->getGenericParams(), genericSig->getRequirements(), QueryTypeSubstitutionMap{subs}, - LookUpConformance(*this, dc)); + LookUpConformance(dc)); switch (result) { case RequirementCheckResult::Failure: @@ -791,7 +793,7 @@ Type TypeChecker::applyUnboundGenericArguments( // Apply the substitution map to the interface type of the declaration. resultType = resultType.subst(QueryTypeSubstitutionMap{subs}, - LookUpConformance(*this, dc), + LookUpConformance(dc), SubstFlags::UseErrorType); // Form a sugared typealias reference. @@ -800,7 +802,7 @@ Type TypeChecker::applyUnboundGenericArguments( auto genericSig = typealias->getGenericSignature(); auto subMap = SubstitutionMap::get(genericSig, QueryTypeSubstitutionMap{subs}, - LookUpConformance(*this, dc)); + LookUpConformance(dc)); resultType = NameAliasType::get(typealias, parentType, subMap, resultType); } @@ -814,19 +816,22 @@ Type TypeChecker::applyUnboundGenericArguments( } /// \brief Diagnose a use of an unbound generic type. -static void diagnoseUnboundGenericType(TypeChecker &tc, Type ty,SourceLoc loc) { +static void diagnoseUnboundGenericType(Type ty, SourceLoc loc) { auto unbound = ty->castTo(); { - InFlightDiagnostic diag = tc.diagnose(loc, + auto &ctx = ty->getASTContext(); + InFlightDiagnostic diag = ctx.Diags.diagnose(loc, diag::generic_type_requires_arguments, ty); if (auto *genericD = unbound->getDecl()) { SmallString<64> genericArgsToAdd; - if (tc.getDefaultGenericArgumentsString(genericArgsToAdd, genericD)) + if (TypeChecker::getDefaultGenericArgumentsString(genericArgsToAdd, + genericD)) diag.fixItInsertAfter(loc, genericArgsToAdd); } } - tc.diagnose(unbound->getDecl(), diag::kind_identifier_declared_here, - DescriptiveDeclKind::GenericType, unbound->getDecl()->getName()); + unbound->getDecl()->diagnose(diag::kind_identifier_declared_here, + DescriptiveDeclKind::GenericType, + unbound->getDecl()->getName()); } // Produce a diagnostic if the type we referenced was an @@ -871,32 +876,38 @@ static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc, auto fromDC = resolution.getDeclContext(); assert(fromDC && "No declaration context for type resolution?"); + ASTContext &ctx = typeDecl->getASTContext(); + auto &diags = ctx.Diags; + auto lazyResolver = ctx.getLazyResolver(); + // Don't validate nominal type declarations during extension binding. if (!options.is(TypeResolverContext::ExtensionBinding) || !isa(typeDecl)) { // Validate the declaration. - TC.validateDeclForNameLookup(typeDecl); + if (lazyResolver) + lazyResolver->resolveDeclSignature(typeDecl); // If we were not able to validate recursively, bail out. if (!typeDecl->hasInterfaceType()) { - TC.diagnose(loc, diag::recursive_type_reference, + diags.diagnose(loc, diag::recursive_type_reference, typeDecl->getDescriptiveKind(), typeDecl->getName()); - TC.diagnose(typeDecl->getLoc(), diag::kind_declared_here, - DescriptiveDeclKind::Type); - return ErrorType::get(TC.Context); + typeDecl->diagnose(diag::kind_declared_here, + DescriptiveDeclKind::Type); + return ErrorType::get(ctx); } } // Resolve the type declaration to a specific type. How this occurs // depends on the current context and where the type was found. Type type = - TC.resolveTypeInContext(typeDecl, foundDC, resolution, options, generic); + TypeChecker::resolveTypeInContext(typeDecl, foundDC, resolution, options, + generic); if (type->is() && !generic && !options.is(TypeResolverContext::TypeAliasDecl) && !options.contains(TypeResolutionFlags::AllowUnboundGenerics)) { - diagnoseUnboundGenericType(TC, type, loc); - return ErrorType::get(TC.Context); + diagnoseUnboundGenericType(type, loc); + return ErrorType::get(ctx); } if (type->hasError() && isa(typeDecl)) { @@ -951,21 +962,21 @@ static std::string getDeclNameFromContext(DeclContext *dc, /// This routine diagnoses a reference to an unknown type, and /// attempts to fix the reference via various means. /// -/// \param tc The type checker through which we should emit the diagnostic. -/// /// \returns either the corrected type, if possible, or an error type to /// that correction failed. -static Type diagnoseUnknownType(TypeChecker &tc, TypeResolution resolution, +static Type diagnoseUnknownType(TypeResolution resolution, Type parentType, SourceRange parentRange, ComponentIdentTypeRepr *comp, TypeResolutionOptions options, NameLookupOptions lookupOptions) { auto dc = resolution.getDeclContext(); + ASTContext &ctx = dc->getASTContext(); + auto &diags = ctx.Diags; // Unqualified lookup case. if (parentType.isNull()) { - if (comp->getIdentifier() == tc.Context.Id_Self && + if (comp->getIdentifier() == ctx.Id_Self && !isa(comp)) { DeclContext *nominalDC = nullptr; NominalTypeDecl *nominal = nullptr; @@ -977,14 +988,14 @@ static Type diagnoseUnknownType(TypeChecker &tc, TypeResolution resolution, // Produce a Fix-It replacing 'Self' with the nominal type name. auto name = getDeclNameFromContext(dc, nominal); - tc.diagnose(comp->getIdLoc(), diag::self_in_nominal, name) + diags.diagnose(comp->getIdLoc(), diag::self_in_nominal, name) .fixItReplace(comp->getIdLoc(), name); // If this is a requirement, replacing 'Self' with a valid type will // result in additional unnecessary diagnostics (does not refer to a // generic parameter or associated type). Simply return an error type. if (options.is(TypeResolverContext::GenericRequirement)) - return ErrorType::get(tc.Context); + return ErrorType::get(ctx); auto type = resolution.mapTypeIntoContext( dc->getInnermostTypeContext()->getSelfInterfaceType()); @@ -994,10 +1005,10 @@ static Type diagnoseUnknownType(TypeChecker &tc, TypeResolution resolution, return type; } // Attempt to refer to 'Self' from a free function. - tc.diagnose(comp->getIdLoc(), diag::dynamic_self_non_method, - dc->getParent()->isLocalContext()); + diags.diagnose(comp->getIdLoc(), diag::dynamic_self_non_method, + dc->getParent()->isLocalContext()); - return ErrorType::get(tc.Context); + return ErrorType::get(ctx); } // Try ignoring access control. @@ -1006,23 +1017,23 @@ static Type diagnoseUnknownType(TypeChecker &tc, TypeResolution resolution, relookupOptions |= NameLookupFlags::KnownPrivate; relookupOptions |= NameLookupFlags::IgnoreAccessControl; auto inaccessibleResults = - tc.lookupUnqualifiedType(lookupDC, comp->getIdentifier(), - comp->getIdLoc(), relookupOptions); + TypeChecker::lookupUnqualifiedType(lookupDC, comp->getIdentifier(), + comp->getIdLoc(), relookupOptions); if (!inaccessibleResults.empty()) { // FIXME: What if the unviable candidates have different levels of access? auto first = cast(inaccessibleResults.front().getValueDecl()); - tc.diagnose(comp->getIdLoc(), diag::candidate_inaccessible, - comp->getIdentifier(), first->getFormalAccess()); + diags.diagnose(comp->getIdLoc(), diag::candidate_inaccessible, + comp->getIdentifier(), first->getFormalAccess()); // FIXME: If any of the candidates (usually just one) are in the same // module we could offer a fix-it. for (auto lookupResult : inaccessibleResults) - tc.diagnose(lookupResult.getValueDecl(), diag::kind_declared_here, - DescriptiveDeclKind::Type); + lookupResult.getValueDecl()->diagnose(diag::kind_declared_here, + DescriptiveDeclKind::Type); // Don't try to recover here; we'll get more access-related diagnostics // downstream if we do. - return ErrorType::get(tc.Context); + return ErrorType::get(ctx); } // Fallback. @@ -1030,74 +1041,73 @@ static Type diagnoseUnknownType(TypeChecker &tc, TypeResolution resolution, SourceRange R = SourceRange(comp->getIdLoc()); // Check if the unknown type is in the type remappings. - auto &Remapped = tc.Context.RemappedTypes; + auto &Remapped = ctx.RemappedTypes; auto TypeName = comp->getIdentifier().str(); auto I = Remapped.find(TypeName); if (I != Remapped.end()) { auto RemappedTy = I->second->getString(); - tc.diagnose(L, diag::use_undeclared_type_did_you_mean, - comp->getIdentifier(), RemappedTy) + diags.diagnose(L, diag::use_undeclared_type_did_you_mean, + comp->getIdentifier(), RemappedTy) .highlight(R) .fixItReplace(R, RemappedTy); // Replace the computed type with the suggested type. - comp->overwriteIdentifier(tc.Context.getIdentifier(RemappedTy)); + comp->overwriteIdentifier(ctx.getIdentifier(RemappedTy)); // HACK: 'NSUInteger' suggests both 'UInt' and 'Int'. - if (TypeName - == tc.Context.getSwiftName(KnownFoundationEntity::NSUInteger)) { - tc.diagnose(L, diag::note_remapped_type, "UInt") + if (TypeName == ctx.getSwiftName(KnownFoundationEntity::NSUInteger)) { + diags.diagnose(L, diag::note_remapped_type, "UInt") .fixItReplace(R, "UInt"); } return I->second; } - tc.diagnose(L, diag::use_undeclared_type, + diags.diagnose(L, diag::use_undeclared_type, comp->getIdentifier()) .highlight(R); - return ErrorType::get(tc.Context); + return ErrorType::get(ctx); } // Qualified lookup case. if (!parentType->mayHaveMembers()) { - tc.diagnose(comp->getIdLoc(), diag::invalid_member_type, - comp->getIdentifier(), parentType) + diags.diagnose(comp->getIdLoc(), diag::invalid_member_type, + comp->getIdentifier(), parentType) .highlight(parentRange); - return ErrorType::get(tc.Context); + return ErrorType::get(ctx); } // Try ignoring access control. NameLookupOptions relookupOptions = lookupOptions; relookupOptions |= NameLookupFlags::KnownPrivate; relookupOptions |= NameLookupFlags::IgnoreAccessControl; - auto inaccessibleMembers = tc.lookupMemberType(dc, parentType, - comp->getIdentifier(), - relookupOptions); + auto inaccessibleMembers = + TypeChecker::lookupMemberType(dc, parentType, comp->getIdentifier(), + relookupOptions); if (inaccessibleMembers) { // FIXME: What if the unviable candidates have different levels of access? const TypeDecl *first = inaccessibleMembers.front().Member; - tc.diagnose(comp->getIdLoc(), diag::candidate_inaccessible, - comp->getIdentifier(), first->getFormalAccess()); + diags.diagnose(comp->getIdLoc(), diag::candidate_inaccessible, + comp->getIdentifier(), first->getFormalAccess()); // FIXME: If any of the candidates (usually just one) are in the same module // we could offer a fix-it. for (auto lookupResult : inaccessibleMembers) - tc.diagnose(lookupResult.Member, diag::kind_declared_here, - DescriptiveDeclKind::Type); + lookupResult.Member->diagnose(diag::kind_declared_here, + DescriptiveDeclKind::Type); // Don't try to recover here; we'll get more access-related diagnostics // downstream if we do. - return ErrorType::get(tc.Context); + return ErrorType::get(ctx); } // FIXME: Typo correction! // Lookup into a type. if (auto moduleType = parentType->getAs()) { - tc.diagnose(comp->getIdLoc(), diag::no_module_type, - comp->getIdentifier(), moduleType->getModule()->getName()); + diags.diagnose(comp->getIdLoc(), diag::no_module_type, + comp->getIdentifier(), moduleType->getModule()->getName()); } else { LookupResult memberLookup; // Let's try to lookup given identifier as a member of the parent type, @@ -1107,23 +1117,24 @@ static Type diagnoseUnknownType(TypeChecker &tc, TypeResolution resolution, memberLookupOptions |= NameLookupFlags::IgnoreAccessControl; memberLookupOptions |= NameLookupFlags::KnownPrivate; - memberLookup = tc.lookupMember(dc, parentType, comp->getIdentifier(), - memberLookupOptions); + memberLookup = TypeChecker::lookupMember(dc, parentType, + comp->getIdentifier(), + memberLookupOptions); // Looks like this is not a member type, but simply a member of parent type. if (!memberLookup.empty()) { auto member = memberLookup[0].getValueDecl(); - tc.diagnose(comp->getIdLoc(), diag::invalid_member_reference, - member->getDescriptiveKind(), comp->getIdentifier(), - parentType) + diags.diagnose(comp->getIdLoc(), diag::invalid_member_reference, + member->getDescriptiveKind(), comp->getIdentifier(), + parentType) .highlight(parentRange); } else { - tc.diagnose(comp->getIdLoc(), diag::invalid_member_type, - comp->getIdentifier(), parentType) - .highlight(parentRange); + diags.diagnose(comp->getIdLoc(), diag::invalid_member_type, + comp->getIdentifier(), parentType) + .highlight(parentRange); } } - return ErrorType::get(tc.Context); + return ErrorType::get(ctx); } /// Resolve the given identifier type representation as an unqualified type, @@ -1240,7 +1251,7 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, if (options.contains(TypeResolutionFlags::SilenceErrors)) return ErrorType::get(ctx); - return diagnoseUnknownType(TC, resolution, nullptr, SourceRange(), comp, + return diagnoseUnknownType(resolution, nullptr, SourceRange(), comp, options, lookupOptions); } @@ -1270,7 +1281,7 @@ static Type resolveNestedIdentTypeComponent( if (memberType->is() && !options.is(TypeResolverContext::TypeAliasDecl) && !options.contains(TypeResolutionFlags::AllowUnboundGenerics)) { - diagnoseUnboundGenericType(TC, memberType, comp->getLoc()); + diagnoseUnboundGenericType(memberType, comp->getLoc()); return ErrorType::get(TC.Context); } @@ -1280,10 +1291,10 @@ static Type resolveNestedIdentTypeComponent( auto maybeDiagnoseBadMemberType = [&](TypeDecl *member, Type memberType, AssociatedTypeDecl *inferredAssocType) { // Diagnose invalid cases. - if (TC.isUnsupportedMemberTypeAccess(parentTy, member)) { + if (TypeChecker::isUnsupportedMemberTypeAccess(parentTy, member)) { if (!options.contains(TypeResolutionFlags::SilenceErrors)) { if (parentTy->is()) - diagnoseUnboundGenericType(TC, parentTy, parentRange.End); + diagnoseUnboundGenericType(parentTy, parentRange.End); else if (parentTy->isExistentialType() && isa(member)) { TC.diagnose(comp->getIdLoc(), diag::assoc_type_outside_of_protocol, @@ -1303,7 +1314,7 @@ static Type resolveNestedIdentTypeComponent( if (options.is(TypeResolverContext::TypeAliasDecl)) { if (parentTy->is()) { if (!options.contains(TypeResolutionFlags::SilenceErrors)) - diagnoseUnboundGenericType(TC, parentTy, parentRange.End); + diagnoseUnboundGenericType(parentTy, parentRange.End); return ErrorType::get(TC.Context); } @@ -1397,7 +1408,7 @@ static Type resolveNestedIdentTypeComponent( if (options.contains(TypeResolutionFlags::SilenceErrors)) return ErrorType::get(TC.Context); - memberType = diagnoseUnknownType(TC, resolution, parentTy, parentRange, + memberType = diagnoseUnknownType(resolution, parentTy, parentRange, comp, options, lookupOptions); member = comp->getBoundDecl(); if (!member) diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 260d8b2e95fdf..afd61a57d89c4 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1156,11 +1156,11 @@ class TypeChecker final : public LazyResolver { /// \param resolution The resolution to perform. /// /// \returns the resolved type. - Type resolveTypeInContext(TypeDecl *typeDecl, - DeclContext *foundDC, - TypeResolution resolution, - TypeResolutionOptions options, - bool isSpecialized); + static Type resolveTypeInContext(TypeDecl *typeDecl, + DeclContext *foundDC, + TypeResolution resolution, + TypeResolutionOptions options, + bool isSpecialized); /// Apply generic arguments to the given type. /// @@ -1498,7 +1498,7 @@ class TypeChecker final : public LazyResolver { /// requirement. /// \param listener The generic check listener used to pick requirements and /// notify callers about diagnosed errors. - RequirementCheckResult checkGenericArguments( + static RequirementCheckResult checkGenericArguments( DeclContext *dc, SourceLoc loc, SourceLoc noteLoc, Type owner, TypeArrayView genericParams, ArrayRef requirements, @@ -1985,10 +1985,10 @@ class TypeChecker final : public LazyResolver { /// /// \returns the conformance, if \c T conforms to the protocol \c Proto, or /// an empty optional. - Optional containsProtocol( - Type T, ProtocolDecl *Proto, - DeclContext *DC, - ConformanceCheckOptions options); + static Optional containsProtocol( + Type T, ProtocolDecl *Proto, + DeclContext *DC, + ConformanceCheckOptions options); /// \brief Determine whether the given type conforms to the given protocol. /// @@ -2007,12 +2007,12 @@ class TypeChecker final : public LazyResolver { /// /// \returns The protocol conformance, if \c T conforms to the /// protocol \c Proto, or \c None. - Optional conformsToProtocol( - Type T, - ProtocolDecl *Proto, - DeclContext *DC, - ConformanceCheckOptions options, - SourceLoc ComplainLoc = SourceLoc()); + static Optional conformsToProtocol( + Type T, + ProtocolDecl *Proto, + DeclContext *DC, + ConformanceCheckOptions options, + SourceLoc ComplainLoc = SourceLoc()); /// Mark the given protocol conformance as "used" from the given declaration /// context. @@ -2023,12 +2023,10 @@ class TypeChecker final : public LazyResolver { /// conformance through a particular declaration context using the given /// type checker. class LookUpConformance { - TypeChecker &tc; DeclContext *dc; public: - explicit LookUpConformance(TypeChecker &tc, DeclContext *dc) - : tc(tc), dc(dc) { } + explicit LookUpConformance(DeclContext *dc) : dc(dc) { } Optional operator()(CanType dependentType, @@ -2124,8 +2122,7 @@ class TypeChecker final : public LazyResolver { /// \brief Check whether the given declaration can be written as a /// member of the given base type. - bool isUnsupportedMemberTypeAccess(Type type, - TypeDecl *typeDecl); + static bool isUnsupportedMemberTypeAccess(Type type, TypeDecl *typeDecl); /// \brief Look up a member type within the given type. /// @@ -2138,10 +2135,10 @@ class TypeChecker final : public LazyResolver { /// \param options Options that control name lookup. /// /// \returns The result of name lookup. - LookupTypeResult lookupMemberType(DeclContext *dc, Type type, - Identifier name, - NameLookupOptions options - = defaultMemberTypeLookupOptions); + static LookupTypeResult lookupMemberType(DeclContext *dc, Type type, + Identifier name, + NameLookupOptions options + = defaultMemberTypeLookupOptions); /// \brief Look up the constructors of the given type. /// @@ -2411,7 +2408,7 @@ class TypeChecker final : public LazyResolver { /// /// Returns true if the arguments list could be constructed, false if for /// some reason it could not. - bool getDefaultGenericArgumentsString( + static bool getDefaultGenericArgumentsString( SmallVectorImpl &buf, const GenericTypeDecl *typeDecl, llvm::function_ref getPreferredType = From 0eaa00a470aa3603abef4fb13f37acd83470f831 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 20 Aug 2018 22:18:43 -0700 Subject: [PATCH 5/7] [Type checker] Separate type resolution from the TypeChecker instance. --- lib/Sema/ConstraintSystem.cpp | 2 +- lib/Sema/TypeCheckType.cpp | 177 +++++++++++++++++++--------------- lib/Sema/TypeChecker.cpp | 18 ---- lib/Sema/TypeChecker.h | 33 +++---- 4 files changed, 112 insertions(+), 118 deletions(-) diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 17013cb4f4d5c..54d9c98fa9705 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -475,7 +475,7 @@ Type ConstraintSystem::openUnboundGenericType(UnboundGenericType *unbound, // pointing at a generic TypeAliasDecl here. If we find a way to // handle generic TypeAliases elsewhere, this can just become a // call to BoundGenericType::get(). - return TC.applyUnboundGenericArguments( + return TypeChecker::applyUnboundGenericArguments( unbound, unboundDecl, SourceLoc(), TypeResolution::forContextual(DC), arguments); } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 61b39f75a6ec1..8bda7a18f553d 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -630,8 +630,8 @@ Type TypeChecker::applyGenericArguments(Type type, genericParams->size(), genericArgs.size(), genericArgs.size() < genericParams->size()) .highlight(generic->getAngleBrackets()); - diagnose(decl, diag::kind_identifier_declared_here, - DescriptiveDeclKind::GenericType, decl->getName()); + decl->diagnose(diag::kind_identifier_declared_here, + DescriptiveDeclKind::GenericType, decl->getName()); } return ErrorType::get(ctx); } @@ -641,12 +641,8 @@ Type TypeChecker::applyGenericArguments(Type type, if (auto nominal = dyn_cast(decl)) { if (nominal->isOptionalDecl()) { // Validate the generic argument. - TypeLoc arg = genericArgs[0]; - if (validateType(arg, resolution, options.withoutContext(true))) - return nullptr; - - Type objectType = arg.getType(); - if (!objectType) + Type objectType = resolveType(genericArgs[0], resolution, options); + if (!objectType || objectType->hasError()) return nullptr; return BoundGenericType::get(nominal, /*parent*/ Type(), objectType); @@ -678,16 +674,10 @@ Type TypeChecker::applyGenericArguments(Type type, SmallVector args; for (auto tyR : genericArgs) { // Propagate failure. - TypeLoc genericArg = tyR; - if (validateType(genericArg, resolution, options)) + Type substTy = resolveType(tyR, resolution, options); + if (!substTy || substTy->hasError()) return ErrorType::get(ctx); - auto substTy = genericArg.getType(); - - // Unsatisfied dependency case. - if (!substTy) - return nullptr; - args.push_back(substTy); } @@ -778,7 +768,7 @@ Type TypeChecker::applyUnboundGenericArguments( switch (result) { case RequirementCheckResult::Failure: case RequirementCheckResult::SubstitutionFailure: - return ErrorType::get(Context); + return ErrorType::get(dc->getASTContext()); case RequirementCheckResult::Success: break; } @@ -838,14 +828,13 @@ static void diagnoseUnboundGenericType(Type ty, SourceLoc loc) { // associated type but the type itself was erroneous. We'll produce a // diagnostic here if the diagnostic for the bad type witness would show up in // a different context. -static void maybeDiagnoseBadConformanceRef(TypeChecker &tc, - DeclContext *dc, +static void maybeDiagnoseBadConformanceRef(DeclContext *dc, Type parentTy, SourceLoc loc, AssociatedTypeDecl *assocType) { // If we weren't given a conformance, go look it up. ProtocolConformance *conformance = nullptr; - if (auto conformanceRef = tc.conformsToProtocol( + if (auto conformanceRef = TypeChecker::conformsToProtocol( parentTy, assocType->getProtocol(), dc, (ConformanceCheckFlags::InExpression | ConformanceCheckFlags::SuppressDependencyTracking | @@ -856,7 +845,8 @@ static void maybeDiagnoseBadConformanceRef(TypeChecker &tc, // If any errors have occurred, don't bother diagnosing this cross-file // issue. - if (tc.Context.Diags.hadAnyError()) + ASTContext &ctx = dc->getASTContext(); + if (ctx.Diags.hadAnyError()) return; auto diagCode = @@ -864,11 +854,11 @@ static void maybeDiagnoseBadConformanceRef(TypeChecker &tc, ? diag::unsupported_recursion_in_associated_type_reference : diag::broken_associated_type_witness; - tc.diagnose(loc, diagCode, assocType->getFullName(), parentTy); + ctx.Diags.diagnose(loc, diagCode, assocType->getFullName(), parentTy); } /// \brief Returns a valid type or ErrorType in case of an error. -static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc, +static Type resolveTypeDecl(TypeDecl *typeDecl, SourceLoc loc, DeclContext *foundDC, TypeResolution resolution, GenericIdentTypeRepr *generic, @@ -911,14 +901,15 @@ static Type resolveTypeDecl(TypeChecker &TC, TypeDecl *typeDecl, SourceLoc loc, } if (type->hasError() && isa(typeDecl)) { - maybeDiagnoseBadConformanceRef(TC, fromDC, + maybeDiagnoseBadConformanceRef(fromDC, foundDC->getDeclaredInterfaceType(), loc, cast(typeDecl)); } if (generic) { // Apply the generic arguments to the type. - type = TC.applyGenericArguments(type, loc, resolution, generic, options); + type = TypeChecker::applyGenericArguments(type, loc, resolution, generic, + options); if (!type) return nullptr; } @@ -1143,8 +1134,7 @@ static Type diagnoseUnknownType(TypeResolution resolution, /// \returns Either the resolved type or a null type, the latter of /// which indicates that some dependencies were unsatisfied. static Type -resolveTopLevelIdentTypeComponent(TypeChecker &TC, - TypeResolution resolution, +resolveTopLevelIdentTypeComponent(TypeResolution resolution, ComponentIdentTypeRepr *comp, TypeResolutionOptions options) { // Short-circuiting. @@ -1156,7 +1146,7 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, // that now. if (auto *typeDecl = comp->getBoundDecl()) { // Resolve the type declaration within this context. - return resolveTypeDecl(TC, typeDecl, comp->getIdLoc(), + return resolveTypeDecl(typeDecl, comp->getIdLoc(), comp->getDeclContext(), resolution, dyn_cast(comp), options); } @@ -1200,7 +1190,7 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, auto *foundDC = entry.getDeclContext(); auto *typeDecl = cast(entry.getValueDecl()); - Type type = resolveTypeDecl(TC, typeDecl, comp->getIdLoc(), + Type type = resolveTypeDecl(typeDecl, comp->getIdLoc(), foundDC, resolution, dyn_cast(comp), options); @@ -1259,30 +1249,49 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, return current; } +static void diagnoseAmbiguousMemberType(Type baseTy, SourceRange baseRange, + Identifier name, SourceLoc nameLoc, + LookupTypeResult &lookup) { + ASTContext &ctx = baseTy->getASTContext(); + auto &diags = ctx.Diags; + if (auto moduleTy = baseTy->getAs()) { + diags.diagnose(nameLoc, diag::ambiguous_module_type, name, + moduleTy->getModule()->getName()) + .highlight(baseRange); + } else { + diags.diagnose(nameLoc, diag::ambiguous_member_type, name, baseTy) + .highlight(baseRange); + } + for (const auto &member : lookup) { + member.Member->diagnose(diag::found_candidate_type, member.MemberType); + } +} + /// Resolve the given identifier type representation as a qualified /// lookup within the given parent type, returning the type it /// references. static Type resolveNestedIdentTypeComponent( - TypeChecker &TC, TypeResolution resolution, Type parentTy, SourceRange parentRange, ComponentIdentTypeRepr *comp, TypeResolutionOptions options) { auto DC = resolution.getDeclContext(); + auto &ctx = DC->getASTContext(); + auto &diags = ctx.Diags; auto maybeApplyGenericArgs = [&](Type memberType) { // If there are generic arguments, apply them now. if (auto genComp = dyn_cast(comp)) { - return TC.applyGenericArguments(memberType, comp->getIdLoc(), - resolution, genComp, options); + return TypeChecker::applyGenericArguments(memberType, comp->getIdLoc(), + resolution, genComp, options); } if (memberType->is() && !options.is(TypeResolverContext::TypeAliasDecl) && !options.contains(TypeResolutionFlags::AllowUnboundGenerics)) { diagnoseUnboundGenericType(memberType, comp->getLoc()); - return ErrorType::get(TC.Context); + return ErrorType::get(ctx); } return memberType; @@ -1297,16 +1306,16 @@ static Type resolveNestedIdentTypeComponent( diagnoseUnboundGenericType(parentTy, parentRange.End); else if (parentTy->isExistentialType() && isa(member)) { - TC.diagnose(comp->getIdLoc(), diag::assoc_type_outside_of_protocol, - comp->getIdentifier()); + diags.diagnose(comp->getIdLoc(), diag::assoc_type_outside_of_protocol, + comp->getIdentifier()); } else if (parentTy->isExistentialType() && isa(member)) { - TC.diagnose(comp->getIdLoc(), diag::typealias_outside_of_protocol, - comp->getIdentifier()); + diags.diagnose(comp->getIdLoc(), diag::typealias_outside_of_protocol, + comp->getIdentifier()); } } - return ErrorType::get(TC.Context); + return ErrorType::get(ctx); } // Only the last component of the underlying type of a type alias may @@ -1316,21 +1325,21 @@ static Type resolveNestedIdentTypeComponent( if (!options.contains(TypeResolutionFlags::SilenceErrors)) diagnoseUnboundGenericType(parentTy, parentRange.End); - return ErrorType::get(TC.Context); + return ErrorType::get(ctx); } } // Diagnose a bad conformance reference if we need to. if (!options.contains(TypeResolutionFlags::SilenceErrors) && inferredAssocType && memberType && memberType->hasError()) { - maybeDiagnoseBadConformanceRef(TC, DC, parentTy, comp->getLoc(), + maybeDiagnoseBadConformanceRef(DC, parentTy, comp->getLoc(), inferredAssocType); } // If we found a reference to an associated type or other member type that // was marked invalid, just return ErrorType to silence downstream errors. if (member->isInvalid()) - return ErrorType::get(TC.Context); + return ErrorType::get(ctx); // At this point, we need to have resolved the type of the member. if (!memberType || memberType->hasError()) @@ -1341,7 +1350,7 @@ static Type resolveNestedIdentTypeComponent( }; // Short-circuiting. - if (comp->isInvalid()) return ErrorType::get(TC.Context); + if (comp->isInvalid()) return ErrorType::get(ctx); // If the parent is a type parameter, the member is a dependent member, // and we skip much of the work below. @@ -1363,8 +1372,9 @@ static Type resolveNestedIdentTypeComponent( // Phase 2: If a declaration has already been bound, use it. if (auto *typeDecl = comp->getBoundDecl()) { - auto memberType = TC.substMemberTypeWithBase(DC->getParentModule(), - typeDecl, parentTy); + auto memberType = + TypeChecker::substMemberTypeWithBase(DC->getParentModule(), typeDecl, + parentTy); return maybeDiagnoseBadMemberType(typeDecl, memberType, nullptr); } @@ -1384,18 +1394,18 @@ static Type resolveNestedIdentTypeComponent( lookupOptions -= NameLookupFlags::ProtocolMembers; LookupTypeResult memberTypes; if (parentTy->mayHaveMembers()) - memberTypes = TC.lookupMemberType(DC, parentTy, comp->getIdentifier(), - lookupOptions); + memberTypes = TypeChecker::lookupMemberType(DC, parentTy, + comp->getIdentifier(), + lookupOptions); // Name lookup was ambiguous. Complain. // FIXME: Could try to apply generic arguments first, and see whether // that resolves things. But do we really want that to succeed? if (memberTypes.size() > 1) { if (!options.contains(TypeResolutionFlags::SilenceErrors)) - TC.diagnoseAmbiguousMemberType(parentTy, parentRange, - comp->getIdentifier(), comp->getIdLoc(), - memberTypes); - return ErrorType::get(TC.Context); + diagnoseAmbiguousMemberType(parentTy, parentRange, comp->getIdentifier(), + comp->getIdLoc(), memberTypes); + return ErrorType::get(ctx); } // If we didn't find anything, complain. @@ -1406,13 +1416,13 @@ static Type resolveNestedIdentTypeComponent( // If we're not allowed to complain or we couldn't fix the // source, bail out. if (options.contains(TypeResolutionFlags::SilenceErrors)) - return ErrorType::get(TC.Context); + return ErrorType::get(ctx); memberType = diagnoseUnknownType(resolution, parentTy, parentRange, comp, options, lookupOptions); member = comp->getBoundDecl(); if (!member) - return ErrorType::get(TC.Context); + return ErrorType::get(ctx); } else { memberType = memberTypes.back().MemberType; member = memberTypes.back().Member; @@ -1424,7 +1434,7 @@ static Type resolveNestedIdentTypeComponent( } static Type resolveIdentTypeComponent( - TypeChecker &TC, TypeResolution resolution, + TypeResolution resolution, ArrayRef components, TypeResolutionOptions options) { auto comp = components.back(); @@ -1432,28 +1442,28 @@ static Type resolveIdentTypeComponent( // The first component uses unqualified lookup. auto parentComps = components.slice(0, components.size()-1); if (parentComps.empty()) { - return resolveTopLevelIdentTypeComponent(TC, resolution, comp, options); + return resolveTopLevelIdentTypeComponent(resolution, comp, options); } // All remaining components use qualified lookup. // Resolve the parent type. - Type parentTy = resolveIdentTypeComponent(TC, resolution, parentComps, - options); + Type parentTy = resolveIdentTypeComponent(resolution, parentComps, options); if (!parentTy || parentTy->hasError()) return parentTy; SourceRange parentRange(parentComps.front()->getIdLoc(), parentComps.back()->getSourceRange().End); // Resolve the nested type. - return resolveNestedIdentTypeComponent(TC, resolution, parentTy, + return resolveNestedIdentTypeComponent(resolution, parentTy, parentRange, comp, options); } static bool diagnoseAvailability(IdentTypeRepr *IdType, - DeclContext *DC, TypeChecker &TC, + DeclContext *DC, bool AllowPotentiallyUnavailableProtocol) { + ASTContext &ctx = DC->getASTContext(); auto componentRange = IdType->getComponentRange(); for (auto comp : componentRange) { if (auto *typeDecl = comp->getBoundDecl()) { @@ -1461,10 +1471,12 @@ static bool diagnoseAvailability(IdentTypeRepr *IdType, // checked for availability. // FIXME: We should try to downgrade these errors to warnings, not just // skip diagnosing them. - if (TC.getLangOpts().isSwiftVersion3() && comp != componentRange.back()) + if (ctx.LangOpts.isSwiftVersion3() && comp != componentRange.back()) continue; - if (diagnoseDeclAvailability(typeDecl, TC, DC, comp->getIdLoc(), + // FIXME: Need to eliminate the type checker argument. + TypeChecker &tc = static_cast(*ctx.getLazyResolver()); + if (diagnoseDeclAvailability(typeDecl, tc, DC, comp->getIdLoc(), AllowPotentiallyUnavailableProtocol, /*SignalOnPotentialUnavailability*/false)) { return true; @@ -1508,23 +1520,24 @@ Type TypeChecker::resolveIdentifierType( IdentTypeRepr *IdType, TypeResolutionOptions options) { auto DC = resolution.getDeclContext(); + ASTContext &ctx = DC->getASTContext(); + auto &diags = ctx.Diags; auto ComponentRange = IdType->getComponentRange(); auto Components = llvm::makeArrayRef(ComponentRange.begin(), ComponentRange.end()); - Type result = resolveIdentTypeComponent(*this, resolution, Components, - options); + Type result = resolveIdentTypeComponent(resolution, Components, options); if (!result) return nullptr; if (auto moduleTy = result->getAs()) { if (!options.contains(TypeResolutionFlags::SilenceErrors)) { auto moduleName = moduleTy->getModule()->getName(); - diagnose(Components.back()->getIdLoc(), - diag::use_undeclared_type, moduleName); - diagnose(Components.back()->getIdLoc(), - diag::note_module_as_type, moduleName); + diags.diagnose(Components.back()->getIdLoc(), + diag::use_undeclared_type, moduleName); + diags.diagnose(Components.back()->getIdLoc(), + diag::note_module_as_type, moduleName); } Components.back()->setInvalid(); - return ErrorType::get(Context); + return ErrorType::get(ctx); } // Hack to apply context-specific @escaping to a typealias with an underlying @@ -1543,10 +1556,10 @@ Type TypeChecker::resolveIdentifierType( if (!options.contains(TypeResolutionFlags::SilenceErrors) && !options.contains(TypeResolutionFlags::AllowUnavailable) && - diagnoseAvailability(IdType, DC, *this, + diagnoseAvailability(IdType, DC, options.contains(TypeResolutionFlags::AllowUnavailableProtocol))) { Components.back()->setInvalid(); - return ErrorType::get(Context); + return ErrorType::get(ctx); } return result; @@ -1585,14 +1598,13 @@ namespace { const auto DefaultResultConvention = ResultConvention::Unowned; class TypeResolver { - TypeChecker &TC; ASTContext &Context; TypeResolution resolution; DeclContext *DC; public: - TypeResolver(TypeChecker &tc, TypeResolution resolution) - : TC(tc), Context(resolution.getDeclContext()->getASTContext()), + explicit TypeResolver(TypeResolution resolution) + : Context(resolution.getDeclContext()->getASTContext()), resolution(resolution), DC(resolution.getDeclContext()) { @@ -1675,9 +1687,10 @@ namespace { Type TypeChecker::resolveType(TypeRepr *TyR, TypeResolution resolution, TypeResolutionOptions options) { - PrettyStackTraceTypeRepr stackTrace(Context, "resolving", TyR); + PrettyStackTraceTypeRepr stackTrace(resolution.getASTContext(), + "resolving", TyR); - TypeResolver typeResolver(*this, resolution); + TypeResolver typeResolver(resolution); auto result = typeResolver.resolveType(TyR, options); // If we resolved down to an error, make sure to mark the typeRepr as invalid @@ -1727,8 +1740,9 @@ Type TypeResolver::resolveType(TypeRepr *repr, TypeResolutionOptions options) { case TypeReprKind::SimpleIdent: case TypeReprKind::GenericIdent: case TypeReprKind::CompoundIdent: - return TC.resolveIdentifierType(resolution, cast(repr), - options); + return TypeChecker::resolveIdentifierType(resolution, + cast(repr), + options); case TypeReprKind::Function: { if (!(options & TypeResolutionFlags::SILType)) { @@ -2363,7 +2377,8 @@ Type TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr, QueryTypeSubstitutionMap{genericArgMap}, [&](CanType depTy, Type replacement, ProtocolDecl *proto) -> ProtocolConformanceRef { - auto result = TC.conformsToProtocol(replacement, proto, DC, + auto result = TypeChecker::conformsToProtocol( + replacement, proto, DC, ConformanceCheckOptions()); // TODO: getSubstitutions callback ought to return Optional. if (!result) { @@ -2510,7 +2525,7 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, selfType = next; } - witnessMethodConformance = TC.conformsToProtocol( + witnessMethodConformance = TypeChecker::conformsToProtocol( selfType, protocolType->getDecl(), DC, ConformanceCheckOptions()); assert(witnessMethodConformance && "found witness_method without matching conformance"); @@ -2773,12 +2788,14 @@ Type TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr, if (auto dictTy = TypeChecker::getDictionaryType(repr->getBrackets().Start, keyTy, valueTy)) { // Check the requirements on the generic arguments. - TC.validateDecl(dictDecl); + if (auto lazyResolver = Context.getLazyResolver()) + lazyResolver->resolveDeclSignature(dictDecl); + auto unboundTy = dictDecl->getDeclaredType()->castTo(); Type args[] = {keyTy, valueTy}; - if (!TC.applyUnboundGenericArguments( + if (!TypeChecker::applyUnboundGenericArguments( unboundTy, dictDecl, repr->getStartLoc(), resolution, args)) { return nullptr; } diff --git a/lib/Sema/TypeChecker.cpp b/lib/Sema/TypeChecker.cpp index 22851b4efa07a..07fe2096e6572 100644 --- a/lib/Sema/TypeChecker.cpp +++ b/lib/Sema/TypeChecker.cpp @@ -988,24 +988,6 @@ OwnedResolver swift::createLazyResolver(ASTContext &Ctx) { &deleteTypeCheckerAndDiags); } -void TypeChecker::diagnoseAmbiguousMemberType(Type baseTy, - SourceRange baseRange, - Identifier name, - SourceLoc nameLoc, - LookupTypeResult &lookup) { - if (auto moduleTy = baseTy->getAs()) { - diagnose(nameLoc, diag::ambiguous_module_type, name, - moduleTy->getModule()->getName()) - .highlight(baseRange); - } else { - diagnose(nameLoc, diag::ambiguous_member_type, name, baseTy) - .highlight(baseRange); - } - for (const auto &member : lookup) { - diagnose(member.Member, diag::found_candidate_type, member.MemberType); - } -} - // checkForForbiddenPrefix is for testing purposes. void TypeChecker::checkForForbiddenPrefix(const Decl *D) { diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index afd61a57d89c4..a6f5962f84662 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -1064,9 +1064,9 @@ class TypeChecker final : public LazyResolver { /// \brief Try to resolve an IdentTypeRepr, returning either the referenced /// Type or an ErrorType in case of error. - Type resolveIdentifierType(TypeResolution resolution, - IdentTypeRepr *IdType, - TypeResolutionOptions options); + static Type resolveIdentifierType(TypeResolution resolution, + IdentTypeRepr *IdType, + TypeResolutionOptions options); /// Bind an UnresolvedDeclRefExpr by performing name lookup and /// returning the resultant expression. Context is the DeclContext used @@ -1112,8 +1112,8 @@ class TypeChecker final : public LazyResolver { /// \param options Options that alter type resolution. /// /// \returns a well-formed type or an ErrorType in case of an error. - Type resolveType(TypeRepr *TyR, TypeResolution resolution, - TypeResolutionOptions options); + static Type resolveType(TypeRepr *TyR, TypeResolution resolution, + TypeResolutionOptions options); void validateDecl(ValueDecl *D); void validateDecl(OperatorDecl *decl); @@ -1179,10 +1179,10 @@ class TypeChecker final : public LazyResolver { /// error. /// /// \see applyUnboundGenericArguments - Type applyGenericArguments(Type type, SourceLoc loc, - TypeResolution resolution, - GenericIdentTypeRepr *generic, - TypeResolutionOptions options); + static Type applyGenericArguments(Type type, SourceLoc loc, + TypeResolution resolution, + GenericIdentTypeRepr *generic, + TypeResolutionOptions options); /// Apply generic arguments to the given type. /// @@ -1200,11 +1200,11 @@ class TypeChecker final : public LazyResolver { /// error. /// /// \see applyGenericArguments - Type applyUnboundGenericArguments(UnboundGenericType *unboundType, - GenericTypeDecl *decl, - SourceLoc loc, - TypeResolution resolution, - ArrayRef genericArgs); + static Type applyUnboundGenericArguments(UnboundGenericType *unboundType, + GenericTypeDecl *decl, + SourceLoc loc, + TypeResolution resolution, + ArrayRef genericArgs); /// \brief Substitute the given base type into the type of the given nested type, /// producing the effective type that the nested type will have. @@ -2162,11 +2162,6 @@ class TypeChecker final : public LazyResolver { /// \brief Look up the Bool type in the standard library. Type lookupBoolType(const DeclContext *dc); - /// Diagnose an ambiguous member type lookup result. - void diagnoseAmbiguousMemberType(Type baseTy, SourceRange baseRange, - Identifier name, SourceLoc nameLoc, - LookupTypeResult &lookup); - /// @} /// \name Overload resolution From 8dc20dfcac72d1cd885f7152fa85b504d4db37ca Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 20 Aug 2018 22:31:59 -0700 Subject: [PATCH 6/7] [Type checker] Move TypeChecker::resolveType() into TypeResolution. Now that type resolution is (almost completely) separated from the type checker instance, move resolveType() out to TypeResolution where it belongs. --- lib/Sema/CSGen.cpp | 4 +- lib/Sema/CSSolver.cpp | 4 +- lib/Sema/CodeSynthesis.cpp | 4 +- lib/Sema/TypeCheckAttr.cpp | 26 ++- lib/Sema/TypeCheckConstraints.cpp | 6 +- lib/Sema/TypeCheckDecl.cpp | 6 +- lib/Sema/TypeCheckRequestFunctions.cpp | 8 +- lib/Sema/TypeCheckType.cpp | 13 +- lib/Sema/TypeCheckType.h | 253 ++++++++++++++++++++++++ lib/Sema/TypeChecker.h | 257 +------------------------ 10 files changed, 288 insertions(+), 293 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 209aee919a4ea..dff169f359975 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1420,8 +1420,8 @@ namespace { Type resolveTypeReferenceInExpression(TypeRepr *rep) { TypeResolutionOptions options(TypeResolverContext::InExpression); options |= TypeResolutionFlags::AllowUnboundGenerics; - return CS.TC.resolveType(rep, TypeResolution::forContextual(CS.DC), - options); + return TypeResolution::forContextual(CS.DC).resolveType(rep, + options); } Type visitTypeExpr(TypeExpr *E) { diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 1d410b05f78fb..4927cce993f56 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -1199,9 +1199,9 @@ void ConstraintSystem::shrink(Expr *expr) { // instead of cloning representative. auto coercionRepr = typeRepr->clone(CS.getASTContext()); // Let's try to resolve coercion type from cloned representative. + auto resolution = TypeResolution::forContextual(CS.DC); auto coercionType = - CS.TC.resolveType(coercionRepr, - TypeResolution::forContextual(CS.DC), None); + resolution.resolveType(coercionRepr, None); // Looks like coercion type is invalid, let's skip this sub-tree. if (coercionType->hasError()) diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index 5cbeca724f56b..a3af603a9e7a6 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -1848,8 +1848,8 @@ static void maybeAddAccessorsToBehaviorStorage(TypeChecker &TC, VarDecl *var) { }; // Try to resolve the behavior to a protocol. - auto behaviorType = TC.resolveType(behavior->ProtocolName, - TypeResolution::forContextual(dc), None); + auto resolution = TypeResolution::forContextual(dc); + auto behaviorType = resolution.resolveType(behavior->ProtocolName, None); if (!behaviorType) { return makeBehaviorAccessors(); } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 0d9a1b85b90e4..d1883a3a3d5db 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1777,12 +1777,13 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) { SmallPtrSet constrainedGenericParams; // Go over the set of requirements and resolve their types. + auto resolution = TypeResolution::forContextual(FD); for (auto &req : trailingWhereClause->getRequirements()) { if (req.getKind() == RequirementReprKind::SameType) { - auto firstType = TC.resolveType(req.getFirstTypeRepr(), - TypeResolution::forContextual(FD), None); - auto secondType = TC.resolveType(req.getSecondTypeRepr(), - TypeResolution::forContextual(FD), None); + auto firstType = resolution.resolveType(req.getFirstTypeRepr(), + None); + auto secondType = resolution.resolveType(req.getSecondTypeRepr(), + None); Type interfaceFirstType; Type interfaceSecondType; @@ -1832,9 +1833,8 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) { } if (req.getKind() == RequirementReprKind::LayoutConstraint) { - auto subjectType = TC.resolveType(req.getSubjectRepr(), - TypeResolution::forContextual(FD), - None); + auto subjectType = resolution.resolveType(req.getSubjectRepr(), + None); Type interfaceSubjectType; // Map types to their interface types. @@ -1870,12 +1870,8 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) { } if (req.getKind() == RequirementReprKind::TypeConstraint) { - auto subjectType = TC.resolveType(req.getSubjectRepr(), - TypeResolution::forContextual(FD), - None); - auto constraint = TC.resolveType(req.getConstraintLoc().getTypeRepr(), - TypeResolution::forContextual(FD), - None); + auto subjectType = resolution.resolveType(req.getSubjectRepr(), None); + auto constraint = resolution.resolveType(req.getConstraintLoc().getTypeRepr(), None); Type interfaceSubjectType; @@ -2043,8 +2039,8 @@ void AttributeChecker::visitImplementsAttr(ImplementsAttr *attr) { options |= TypeResolutionFlags::AllowUnboundGenerics; DeclContext *DC = D->getDeclContext(); - Type T = TC.resolveType(ProtoTypeLoc.getTypeRepr(), - TypeResolution::forContextual(DC), options); + auto resolution = TypeResolution::forContextual(DC); + Type T = resolution.resolveType(ProtoTypeLoc.getTypeRepr(), options); ProtoTypeLoc.setType(T); // Definite error-types were already diagnosed in resolveType. diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index e1329efd51a01..2b2b058fcea46 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -1036,7 +1036,7 @@ namespace { if (auto PlaceholderE = dyn_cast(expr)) { if (!PlaceholderE->getTypeLoc().isNull()) { if (!TC.validateType(PlaceholderE->getTypeLoc(), - TypeResolution::forContextual(DC))) + TypeResolution::forContextual(DC), None)) expr->setType(PlaceholderE->getTypeLoc().getType()); } return finish(true, expr); @@ -1347,7 +1347,7 @@ TypeExpr *PreCheckExpression::simplifyNestedTypeExpr(UnresolvedDotExpr *UDE) { options |= TypeResolutionFlags::AllowUnboundGenerics; options |= TypeResolutionFlags::AllowUnavailable; auto resolution = TypeResolution::forContextual(DC); - auto BaseTy = TC.resolveType(InnerTypeRepr, resolution, options); + auto BaseTy = resolution.resolveType(InnerTypeRepr, options); if (BaseTy && BaseTy->mayHaveMembers()) { auto lookupOptions = defaultMemberLookupOptions; @@ -1864,7 +1864,7 @@ Expr *PreCheckExpression::simplifyTypeConstructionWithLiteralArg(Expr *E) { TypeResolutionOptions options(TypeResolverContext::InExpression); options |= TypeResolutionFlags::AllowUnboundGenerics; auto resolution = TypeResolution::forContextual(DC); - type = TC.resolveType(rep, resolution, options); + type = resolution.resolveType(rep, options); typeExpr->getTypeLoc().setType(type); } diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index b0d25df175dd0..e9ac3ad138ede 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -3818,8 +3818,10 @@ void TypeChecker::validateDecl(ValueDecl *D) { TypeLoc &defaultDefinition = assocType->getDefaultDefinitionLoc(); if (!defaultDefinition.isNull()) { if (validateType( - defaultDefinition, - TypeResolution::forContextual(assocType->getDeclContext()))) { + defaultDefinition, + TypeResolution::forContextual( + assocType->getDeclContext()), + None)) { defaultDefinition.setInvalidType(Context); } else { // associatedtype X = X is invalid diff --git a/lib/Sema/TypeCheckRequestFunctions.cpp b/lib/Sema/TypeCheckRequestFunctions.cpp index 15a4667ccd464..2031f27f8cbdf 100644 --- a/lib/Sema/TypeCheckRequestFunctions.cpp +++ b/lib/Sema/TypeCheckRequestFunctions.cpp @@ -45,17 +45,13 @@ InheritedTypeRequest::evaluate( isa(dc) ? TypeResolution::forStructural(dc) : TypeResolution::forContextual(dc); - auto lazyResolver = dc->getASTContext().getLazyResolver(); - assert(lazyResolver && "Cannot resolve inherited type at this point"); - - TypeChecker &tc = *static_cast(lazyResolver); TypeLoc &typeLoc = getTypeLoc(decl, index); Type inheritedType = - tc.resolveType(typeLoc.getTypeRepr(), resolution, options); + resolution.resolveType(typeLoc.getTypeRepr(), options); if (inheritedType && !isa(dc)) inheritedType = inheritedType->mapTypeOutOfContext(); - return inheritedType ? inheritedType : ErrorType::get(tc.Context); + return inheritedType ? inheritedType : ErrorType::get(dc->getASTContext()); } llvm::Expected diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 8bda7a18f553d..6795697712fb9 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -641,7 +641,7 @@ Type TypeChecker::applyGenericArguments(Type type, if (auto nominal = dyn_cast(decl)) { if (nominal->isOptionalDecl()) { // Validate the generic argument. - Type objectType = resolveType(genericArgs[0], resolution, options); + Type objectType = resolution.resolveType(genericArgs[0], options); if (!objectType || objectType->hasError()) return nullptr; @@ -674,7 +674,7 @@ Type TypeChecker::applyGenericArguments(Type type, SmallVector args; for (auto tyR : genericArgs) { // Propagate failure. - Type substTy = resolveType(tyR, resolution, options); + Type substTy = resolution.resolveType(tyR, options); if (!substTy || substTy->hasError()) return ErrorType::get(ctx); @@ -1576,7 +1576,7 @@ bool TypeChecker::validateType(TypeLoc &Loc, TypeResolution resolution, Type type = Loc.getType(); if (type.isNull()) { - type = resolveType(Loc.getTypeRepr(), resolution, options); + type = resolution.resolveType(Loc.getTypeRepr(), options); if (!type) { type = ErrorType::get(Context); @@ -1685,12 +1685,11 @@ namespace { }; } // end anonymous namespace -Type TypeChecker::resolveType(TypeRepr *TyR, TypeResolution resolution, +Type TypeResolution::resolveType(TypeRepr *TyR, TypeResolutionOptions options) { - PrettyStackTraceTypeRepr stackTrace(resolution.getASTContext(), - "resolving", TyR); + PrettyStackTraceTypeRepr stackTrace(getASTContext(), "resolving", TyR); - TypeResolver typeResolver(resolution); + TypeResolver typeResolver(*this); auto result = typeResolver.resolveType(TyR, options); // If we resolved down to an error, make sure to mark the typeRepr as invalid diff --git a/lib/Sema/TypeCheckType.h b/lib/Sema/TypeCheckType.h index 3ebcd18c4cb92..e6310a3e454bc 100644 --- a/lib/Sema/TypeCheckType.h +++ b/lib/Sema/TypeCheckType.h @@ -18,6 +18,243 @@ namespace swift { +/// Flags that describe the context of type checking a pattern or +/// type. +enum class TypeResolutionFlags : uint16_t { + /// Whether to allow unspecified types within a pattern. + AllowUnspecifiedTypes = 1 << 0, + + /// Whether to allow unbound generic types. + AllowUnboundGenerics = 1 << 1, + + /// Whether an unavailable protocol can be referenced. + AllowUnavailableProtocol = 1 << 2, + + /// Whether we should allow references to unavailable types. + AllowUnavailable = 1 << 3, + + /// Whether the given type can override the type of a typed pattern. + OverrideType = 1 << 4, + + /// Whether we are validating the type for SIL. + // FIXME: Move this flag to TypeResolverContext. + SILType = 1 << 5, + + /// Whether we are parsing a SIL file. Not the same as SILType, + /// because the latter is not set if we're parsing an AST type. + SILMode = 1 << 6, + + /// Whether this is a resolution based on a non-inferred type pattern. + FromNonInferredPattern = 1 << 7, + + /// Whether this type resolution is guaranteed not to affect downstream files. + KnownNonCascadingDependency = 1 << 8, + + /// Whether we are at the direct base of a type expression. + Direct = 1 << 9, + + /// Whether we should not produce diagnostics if the type is invalid. + SilenceErrors = 1 << 10, +}; + +/// Type resolution contexts that require special handling. +enum class TypeResolverContext : uint8_t { + /// No special type handling is required. + None, + + /// Whether we are checking the parameter list of a function. + AbstractFunctionDecl, + + /// Whether we are checking the parameter list of a subscript. + SubscriptDecl, + + /// Whether we are checking the parameter list of a closure. + ClosureExpr, + + /// Whether we are in the input type of a function, or under one level of + /// tuple type. This is not set for multi-level tuple arguments. + /// See also: TypeResolutionFlags::Direct + FunctionInput, + + /// Whether this is a variadic function input. + VariadicFunctionInput, + + /// Whether we are in the result type of a function, including multi-level + /// tuple return values. See also: TypeResolutionFlags::Direct + FunctionResult, + + /// Whether we are in the result type of a function body that is + /// known to produce dynamic Self. + DynamicSelfResult, + + /// Whether we are in a protocol's where clause + ProtocolWhereClause, + + /// Whether this is a pattern binding entry. + PatternBindingDecl, + + /// Whether we are the variable type in a for/in statement. + ForEachStmt, + + /// Whether we are binding an extension declaration, which limits + /// the lookup. + ExtensionBinding, + + /// Whether this type is being used in an expression or local declaration. + /// + /// This affects what sort of dependencies are recorded when resolving the + /// type. + InExpression, + + /// Whether this type is being used in a cast or coercion expression. + ExplicitCastExpr, + + /// Whether this type is the value carried in an enum case. + EnumElementDecl, + + /// Whether this is the payload subpattern of an enum pattern. + EnumPatternPayload, + + /// Whether we are checking the underlying type of a typealias. + TypeAliasDecl, + + /// Whether we are in a requirement of a generic declaration + GenericRequirement, + + /// Whether we are in a type argument for an optional + ImmediateOptionalTypeArgument, + + /// Whether this is the type of an editor placeholder. + EditorPlaceholderExpr, +}; + +/// Options that determine how type resolution should work. +class TypeResolutionOptions { + using Context = TypeResolverContext; + + // The "base" type resolution context. This never changes. + Context base = Context::None; + // The current type resolution context. + Context context = Context::None; + // TypeResolutionFlags + uint16_t flags = 0; + static_assert(sizeof(flags) == sizeof(TypeResolutionFlags), + "Flags size error"); + +public: + ~TypeResolutionOptions() = default; + TypeResolutionOptions(const TypeResolutionOptions &) = default; + TypeResolutionOptions(TypeResolutionOptions &&) = default; + TypeResolutionOptions &operator =(const TypeResolutionOptions &) = default; + TypeResolutionOptions &operator =(TypeResolutionOptions &&) = default; + + // NOTE: Use either setContext() or explicit construction and assignment. + void operator =(const Context &) = delete; + void operator =(Context &&) = delete; + + // NOTE: "None" might be more permissive than one wants, therefore no + // reasonable default context is possible. + TypeResolutionOptions() = delete; + + TypeResolutionOptions(Context context) : base(context), context(context), + flags(unsigned(TypeResolutionFlags::Direct)) {} + // Helper forwarding constructors: + TypeResolutionOptions(llvm::NoneType) : TypeResolutionOptions(Context::None){} + + /// Test the current type resolution base context. + bool hasBase(Context context) const { return base == context; } + + /// Get the base type resolution context. + Context getBaseContext() const { return base; } + + /// Test the current type resolution context. + bool is(Context context) const { return this->context == context; } + + /// Get the current type resolution context. + Context getContext() const { return context; } + /// Set the current type resolution context. + void setContext(Context newContext) { + context = newContext; + flags &= ~unsigned(TypeResolutionFlags::Direct); + } + void setContext(llvm::NoneType) { setContext(Context::None); } + + /// Get the current flags. + TypeResolutionFlags getFlags() const { return TypeResolutionFlags(flags); } + + /// Is this type resolution context an expression. + bool isAnyExpr() const { + switch (base) { + case Context::InExpression: + case Context::ExplicitCastExpr: + case Context::ForEachStmt: + case Context::PatternBindingDecl: + case Context::EditorPlaceholderExpr: + case Context::ClosureExpr: + return true; + case Context::None: + case Context::FunctionInput: + case Context::VariadicFunctionInput: + case Context::FunctionResult: + case Context::DynamicSelfResult: + case Context::ProtocolWhereClause: + case Context::ExtensionBinding: + case Context::SubscriptDecl: + case Context::EnumElementDecl: + case Context::EnumPatternPayload: + case Context::TypeAliasDecl: + case Context::GenericRequirement: + case Context::ImmediateOptionalTypeArgument: + case Context::AbstractFunctionDecl: + return false; + } + } + + /// Determine whether all of the given options are set. + bool contains(TypeResolutionFlags set) const { + return !static_cast(unsigned(set) & ~unsigned(flags)); + } + + /// Produce type resolution options with additional flags. + friend TypeResolutionOptions operator|(TypeResolutionOptions lhs, + TypeResolutionFlags rhs) { + return lhs |= rhs; + } + + /// Merge additional flags into type resolution options. + friend TypeResolutionOptions &operator|=(TypeResolutionOptions &lhs, + TypeResolutionFlags rhs) { + lhs.flags |= unsigned(rhs); + return lhs; + } + + /// Test whether any given flag is set in the type resolution options. + friend bool operator&(TypeResolutionOptions lhs, TypeResolutionFlags rhs) { + return lhs.flags & unsigned(rhs); + } + + /// Produce type resolution options with removed flags. + friend TypeResolutionOptions operator-(TypeResolutionOptions lhs, + TypeResolutionFlags rhs) { + return lhs -= rhs; + } + + /// Remove the flags from the type resolution options. + friend TypeResolutionOptions &operator-=(TypeResolutionOptions &lhs, + TypeResolutionFlags rhs) { + lhs.flags &= ~unsigned(rhs); + return lhs; + } + /// Strip the contextual options from the given type resolution options. + inline TypeResolutionOptions withoutContext(bool preserveSIL = false) const { + auto copy = *this; + copy.setContext(None); + // FIXME: Move SILType to TypeResolverContext. + if (!preserveSIL) copy -= TypeResolutionFlags::SILType; + return copy; + } +}; + /// Handles the resolution of types within a given declaration context, /// which might involve resolving generic parameters to a particular /// stage. @@ -78,16 +315,32 @@ class TypeResolution { /// no generic signature to resolve types. GenericSignature *getGenericSignature() const; + /// \brief Resolves a TypeRepr to a type. + /// + /// Performs name binding, checking of generic arguments, and so on in order + /// to create a well-formed type. + /// + /// \param TyR The type representation to check. + /// + /// \param options Options that alter type resolution. + /// + /// \returns a well-formed type or an ErrorType in case of an error. + Type resolveType(TypeRepr *TyR, TypeResolutionOptions options); + /// Whether this type resolution uses archetypes (vs. generic parameters). bool usesArchetypes() const; /// Map the given type (that involves generic parameters) Type mapTypeIntoContext(Type type) const; + /// Resolve a reference to a member type of the given (dependent) base and + /// name. Type resolveDependentMemberType(Type baseTy, DeclContext *DC, SourceRange baseRange, ComponentIdentTypeRepr *ref) const; + /// Determine whether the given two types are equivalent within this + /// type resolution context. bool areSameType(Type type1, Type type2) const; }; diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index a6f5962f84662..d16f394c15161 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -41,6 +41,7 @@ class NormalProtocolConformance; class TopLevelContext; class TypeChecker; class TypeResolution; +class TypeResolutionOptions; class TypoCorrectionResults; class ExprPattern; class SynthesizedFunction; @@ -457,243 +458,6 @@ enum class RequirementCheckResult { Success, Failure, SubstitutionFailure }; -/// Flags that describe the context of type checking a pattern or -/// type. -enum class TypeResolutionFlags : uint16_t { - /// Whether to allow unspecified types within a pattern. - AllowUnspecifiedTypes = 1 << 0, - - /// Whether to allow unbound generic types. - AllowUnboundGenerics = 1 << 1, - - /// Whether an unavailable protocol can be referenced. - AllowUnavailableProtocol = 1 << 2, - - /// Whether we should allow references to unavailable types. - AllowUnavailable = 1 << 3, - - /// Whether the given type can override the type of a typed pattern. - OverrideType = 1 << 4, - - /// Whether we are validating the type for SIL. - // FIXME: Move this flag to TypeResolverContext. - SILType = 1 << 5, - - /// Whether we are parsing a SIL file. Not the same as SILType, - /// because the latter is not set if we're parsing an AST type. - SILMode = 1 << 6, - - /// Whether this is a resolution based on a non-inferred type pattern. - FromNonInferredPattern = 1 << 7, - - /// Whether this type resolution is guaranteed not to affect downstream files. - KnownNonCascadingDependency = 1 << 8, - - /// Whether we are at the direct base of a type expression. - Direct = 1 << 9, - - /// Whether we should not produce diagnostics if the type is invalid. - SilenceErrors = 1 << 10, -}; - -/// Type resolution contexts that require special handling. -enum class TypeResolverContext : uint8_t { - /// No special type handling is required. - None, - - /// Whether we are checking the parameter list of a function. - AbstractFunctionDecl, - - /// Whether we are checking the parameter list of a subscript. - SubscriptDecl, - - /// Whether we are checking the parameter list of a closure. - ClosureExpr, - - /// Whether we are in the input type of a function, or under one level of - /// tuple type. This is not set for multi-level tuple arguments. - /// See also: TypeResolutionFlags::Direct - FunctionInput, - - /// Whether this is a variadic function input. - VariadicFunctionInput, - - /// Whether we are in the result type of a function, including multi-level - /// tuple return values. See also: TypeResolutionFlags::Direct - FunctionResult, - - /// Whether we are in the result type of a function body that is - /// known to produce dynamic Self. - DynamicSelfResult, - - /// Whether we are in a protocol's where clause - ProtocolWhereClause, - - /// Whether this is a pattern binding entry. - PatternBindingDecl, - - /// Whether we are the variable type in a for/in statement. - ForEachStmt, - - /// Whether we are binding an extension declaration, which limits - /// the lookup. - ExtensionBinding, - - /// Whether this type is being used in an expression or local declaration. - /// - /// This affects what sort of dependencies are recorded when resolving the - /// type. - InExpression, - - /// Whether this type is being used in a cast or coercion expression. - ExplicitCastExpr, - - /// Whether this type is the value carried in an enum case. - EnumElementDecl, - - /// Whether this is the payload subpattern of an enum pattern. - EnumPatternPayload, - - /// Whether we are checking the underlying type of a typealias. - TypeAliasDecl, - - /// Whether we are in a requirement of a generic declaration - GenericRequirement, - - /// Whether we are in a type argument for an optional - ImmediateOptionalTypeArgument, - - /// Whether this is the type of an editor placeholder. - EditorPlaceholderExpr, -}; - -/// Options that determine how type resolution should work. -class TypeResolutionOptions { - using Context = TypeResolverContext; - - // The "base" type resolution context. This never changes. - Context base = Context::None; - // The current type resolution context. - Context context = Context::None; - // TypeResolutionFlags - uint16_t flags = 0; - static_assert(sizeof(flags) == sizeof(TypeResolutionFlags), - "Flags size error"); - -public: - ~TypeResolutionOptions() = default; - TypeResolutionOptions(const TypeResolutionOptions &) = default; - TypeResolutionOptions(TypeResolutionOptions &&) = default; - TypeResolutionOptions &operator =(const TypeResolutionOptions &) = default; - TypeResolutionOptions &operator =(TypeResolutionOptions &&) = default; - - // NOTE: Use either setContext() or explicit construction and assignment. - void operator =(const Context &) = delete; - void operator =(Context &&) = delete; - - // NOTE: "None" might be more permissive than one wants, therefore no - // reasonable default context is possible. - TypeResolutionOptions() = delete; - - TypeResolutionOptions(Context context) : base(context), context(context), - flags(unsigned(TypeResolutionFlags::Direct)) {} - // Helper forwarding constructors: - TypeResolutionOptions(llvm::NoneType) : TypeResolutionOptions(Context::None){} - - /// Test the current type resolution base context. - bool hasBase(Context context) const { return base == context; } - - /// Get the base type resolution context. - Context getBaseContext() const { return base; } - - /// Test the current type resolution context. - bool is(Context context) const { return this->context == context; } - - /// Get the current type resolution context. - Context getContext() const { return context; } - /// Set the current type resolution context. - void setContext(Context newContext) { - context = newContext; - flags &= ~unsigned(TypeResolutionFlags::Direct); - } - void setContext(llvm::NoneType) { setContext(Context::None); } - - /// Get the current flags. - TypeResolutionFlags getFlags() const { return TypeResolutionFlags(flags); } - - /// Is this type resolution context an expression. - bool isAnyExpr() const { - switch (base) { - case Context::InExpression: - case Context::ExplicitCastExpr: - case Context::ForEachStmt: - case Context::PatternBindingDecl: - case Context::EditorPlaceholderExpr: - case Context::ClosureExpr: - return true; - case Context::None: - case Context::FunctionInput: - case Context::VariadicFunctionInput: - case Context::FunctionResult: - case Context::DynamicSelfResult: - case Context::ProtocolWhereClause: - case Context::ExtensionBinding: - case Context::SubscriptDecl: - case Context::EnumElementDecl: - case Context::EnumPatternPayload: - case Context::TypeAliasDecl: - case Context::GenericRequirement: - case Context::ImmediateOptionalTypeArgument: - case Context::AbstractFunctionDecl: - return false; - } - } - - /// Determine whether all of the given options are set. - bool contains(TypeResolutionFlags set) const { - return !static_cast(unsigned(set) & ~unsigned(flags)); - } - - /// Produce type resolution options with additional flags. - friend TypeResolutionOptions operator|(TypeResolutionOptions lhs, - TypeResolutionFlags rhs) { - return lhs |= rhs; - } - - /// Merge additional flags into type resolution options. - friend TypeResolutionOptions &operator|=(TypeResolutionOptions &lhs, - TypeResolutionFlags rhs) { - lhs.flags |= unsigned(rhs); - return lhs; - } - - /// Test whether any given flag is set in the type resolution options. - friend bool operator&(TypeResolutionOptions lhs, TypeResolutionFlags rhs) { - return lhs.flags & unsigned(rhs); - } - - /// Produce type resolution options with removed flags. - friend TypeResolutionOptions operator-(TypeResolutionOptions lhs, - TypeResolutionFlags rhs) { - return lhs -= rhs; - } - - /// Remove the flags from the type resolution options. - friend TypeResolutionOptions &operator-=(TypeResolutionOptions &lhs, - TypeResolutionFlags rhs) { - lhs.flags &= ~unsigned(rhs); - return lhs; - } - /// Strip the contextual options from the given type resolution options. - inline TypeResolutionOptions withoutContext(bool preserveSIL = false) const { - auto copy = *this; - copy.setContext(None); - // FIXME: Move SILType to TypeResolverContext. - if (!preserveSIL) copy -= TypeResolutionFlags::SILType; - return copy; - } -}; - /// Flags that control protocol conformance checking. enum class ConformanceCheckFlags { /// Whether we're performing the check from within an expression. @@ -1088,7 +852,7 @@ class TypeChecker final : public LazyResolver { /// /// \returns true if type validation failed, or false otherwise. bool validateType(TypeLoc &Loc, TypeResolution resolution, - TypeResolutionOptions options = None); + TypeResolutionOptions options); /// Check for unsupported protocol types in the given declaration. void checkUnsupportedProtocolType(Decl *decl); @@ -1100,21 +864,6 @@ class TypeChecker final : public LazyResolver { GenericEnvironment *handleSILGenericParams(GenericParamList *genericParams, DeclContext *DC); - /// \brief Resolves a TypeRepr to a type. - /// - /// Performs name binding, checking of generic arguments, and so on in order - /// to create a well-formed type. - /// - /// \param TyR The type representation to check. - /// - /// \param resolution The type resolution to perform. - /// - /// \param options Options that alter type resolution. - /// - /// \returns a well-formed type or an ErrorType in case of an error. - static Type resolveType(TypeRepr *TyR, TypeResolution resolution, - TypeResolutionOptions options); - void validateDecl(ValueDecl *D); void validateDecl(OperatorDecl *decl); void validateDecl(PrecedenceGroupDecl *decl); @@ -1456,7 +1205,7 @@ class TypeChecker final : public LazyResolver { bool validateRequirement(SourceLoc whereLoc, RequirementRepr &req, TypeResolution resolution, - TypeResolutionOptions options = None); + TypeResolutionOptions options); /// Validate the given requirements. void validateRequirements(SourceLoc whereLoc, From e67d78d9198ddd6e98045eb13338997dd22bd47f Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 20 Aug 2018 23:59:30 -0700 Subject: [PATCH 7/7] Update test case for better recursion detection. --- test/decl/protocol/req/recursion.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/decl/protocol/req/recursion.swift b/test/decl/protocol/req/recursion.swift index 2c7f456ed3ccc..59c1217b33b33 100644 --- a/test/decl/protocol/req/recursion.swift +++ b/test/decl/protocol/req/recursion.swift @@ -25,12 +25,13 @@ protocol CircularAssocTypeDefault { associatedtype Z3 = Z2 // expected-note@-1{{protocol requires nested type 'Z3'; do you want to add it?}} - associatedtype Z4 = Self.Z4 // expected-error{{associated type 'Z4' is not a member type of 'Self'}} - // expected-note@-1{{protocol requires nested type 'Z4'; do you want to add it?}} + associatedtype Z4 = Self.Z4 // expected-error{{associated type 'Z4' references itself}} + // expected-note@-1{{type declared here}} + // expected-note@-2{{protocol requires nested type 'Z4'; do you want to add it?}} associatedtype Z5 = Self.Z6 // expected-note@-1{{protocol requires nested type 'Z5'; do you want to add it?}} - associatedtype Z6 = Self.Z5 // expected-error{{associated type 'Z5' is not a member type of 'Self'}} + associatedtype Z6 = Self.Z5 // expected-note@-1{{protocol requires nested type 'Z6'; do you want to add it?}} }