From d54bbc664a8086ae8b8a105607917edd8a8facb8 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 10:54:37 -0700 Subject: [PATCH 01/14] [Gardening] Remove TypeChecker::validateType Entrypoint --- lib/Sema/TypeChecker.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index c3bd2d9384d70..c971d3bc34aa8 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -358,20 +358,6 @@ Type getUInt8Type(ASTContext &ctx); /// for the lookup. Expr *resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *Context); -/// Validate the given type. -/// -/// Type validation performs name lookup, checking of generic arguments, -/// and so on to determine whether the given type is well-formed and can -/// be used as a type. -/// -/// \param Loc The type (with source location information) to validate. -/// If the type has already been validated, returns immediately. -/// -/// \param resolution The type resolution being performed. -/// -/// \returns true if type validation failed, or false otherwise. -bool validateType(TypeLoc &Loc, TypeResolution resolution); - /// Check for unsupported protocol types in the given declaration. void checkUnsupportedProtocolType(Decl *decl); From 4c0c7daf3f8fac23bc0a48027203680d703de544 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 10:58:17 -0700 Subject: [PATCH 02/14] [NFC] Fixup TypeChecker::getArraySliceType To Not Return Type() --- lib/Sema/CSGen.cpp | 2 +- lib/Sema/TypeCheckDecl.cpp | 2 +- lib/Sema/TypeCheckType.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 15b1d5ee7a85a..376baa96168a0 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2938,7 +2938,7 @@ namespace { // Try to build the appropriate type for a variadic argument list of // the fresh element type. If that failed, just bail out. auto array = TypeChecker::getArraySliceType(expr->getLoc(), element); - if (!array) return element; + if (array->hasError()) return element; // Require the operand to be convertible to the array type. CS.addConstraint(ConstraintKind::Conversion, diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 6a5f8c7ac3b56..333583258b1b6 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2101,7 +2101,7 @@ static Type validateParameterType(ParamDecl *decl) { if (decl->isVariadic()) { Ty = TypeChecker::getArraySliceType(decl->getStartLoc(), Ty); - if (Ty.isNull()) { + if (Ty->hasError()) { decl->setInvalid(); return ErrorType::get(ctx); } diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 3f368011f8aa1..7316d0d9adbbf 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -364,7 +364,7 @@ Type TypeChecker::getArraySliceType(SourceLoc loc, Type elementType) { ASTContext &ctx = elementType->getASTContext(); if (!ctx.getArrayDecl()) { ctx.Diags.diagnose(loc, diag::sugar_type_not_found, 0); - return Type(); + return ErrorType::get(ctx); } return ArraySliceType::get(elementType); From bd6724c6d83196b7105adcb82b76edee9eefc69f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 11:17:21 -0700 Subject: [PATCH 03/14] [NFC] Collapse TypeChecker::getDictionaryType This method's only caller was using this to form a substituted DictionaryType, but also using TypeChecker::applyUnboundGenericArguments. We need to use the latter unconditionally so we actually check the requirements on DictionaryType and emit diagnostics. Also clean up resolveDictionaryType so it consistently returns ErrorTypes. --- lib/Sema/TypeCheckType.cpp | 51 ++++++++++++++++---------------------- lib/Sema/TypeChecker.h | 1 - 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 7316d0d9adbbf..09c6dd091721d 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -370,17 +370,6 @@ Type TypeChecker::getArraySliceType(SourceLoc loc, Type elementType) { return ArraySliceType::get(elementType); } -Type TypeChecker::getDictionaryType(SourceLoc loc, Type keyType, - Type valueType) { - ASTContext &ctx = keyType->getASTContext(); - if (!ctx.getDictionaryDecl()) { - ctx.Diags.diagnose(loc, diag::sugar_type_not_found, 3); - return Type(); - } - - return DictionaryType::get(keyType, valueType); -} - Type TypeChecker::getOptionalType(SourceLoc loc, Type elementType) { ASTContext &ctx = elementType->getASTContext(); if (!ctx.getOptionalDecl()) { @@ -3305,11 +3294,13 @@ Type TypeResolver::resolveSpecifierTypeRepr(SpecifierTypeRepr *repr, Type TypeResolver::resolveArrayType(ArrayTypeRepr *repr, TypeResolutionOptions options) { Type baseTy = resolveType(repr->getBase(), options.withoutContext()); - if (!baseTy || baseTy->hasError()) return baseTy; + if (!baseTy || baseTy->hasError()) { + return ErrorType::get(Context); + } auto sliceTy = TypeChecker::getArraySliceType(repr->getBrackets().Start, baseTy); - if (!sliceTy) + if (sliceTy->hasError()) return ErrorType::get(Context); return sliceTy; @@ -3320,28 +3311,30 @@ Type TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr, options = adjustOptionsForGenericArgs(options); Type keyTy = resolveType(repr->getKey(), options.withoutContext()); - if (!keyTy || keyTy->hasError()) return keyTy; + if (!keyTy || keyTy->hasError()) { + return ErrorType::get(Context); + } Type valueTy = resolveType(repr->getValue(), options.withoutContext()); - if (!valueTy || valueTy->hasError()) return valueTy; + if (!valueTy || valueTy->hasError()) { + return ErrorType::get(Context); + } auto dictDecl = Context.getDictionaryDecl(); - - if (auto dictTy = TypeChecker::getDictionaryType(repr->getBrackets().Start, - keyTy, valueTy)) { - auto unboundTy = dictDecl->getDeclaredType()->castTo(); - - Type args[] = {keyTy, valueTy}; - - if (!TypeChecker::applyUnboundGenericArguments( - unboundTy, dictDecl, repr->getStartLoc(), resolution, args)) { - return nullptr; - } - - return dictTy; + if (!dictDecl) { + Context.Diags.diagnose(repr->getBrackets().Start, + diag::sugar_type_not_found, 3); + return ErrorType::get(Context); } - return ErrorType::get(Context); + auto unboundTy = dictDecl->getDeclaredType()->castTo(); + Type args[] = {keyTy, valueTy}; + if (!TypeChecker::applyUnboundGenericArguments( + unboundTy, dictDecl, repr->getStartLoc(), resolution, args)) { + assert(Context.Diags.hadAnyError()); + return ErrorType::get(Context); + } + return DictionaryType::get(keyTy, valueTy); } Type TypeResolver::resolveOptionalType(OptionalTypeRepr *repr, diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index c971d3bc34aa8..2cb71edf98274 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -345,7 +345,6 @@ enum class CheckedCastContextKind { namespace TypeChecker { Type getArraySliceType(SourceLoc loc, Type elementType); -Type getDictionaryType(SourceLoc loc, Type keyType, Type valueType); Type getOptionalType(SourceLoc loc, Type elementType); Type getStringType(ASTContext &ctx); Type getSubstringType(ASTContext &ctx); From d81f1482c38ce2010ebaef9d9d1dc3085ccbdb56 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 11:24:44 -0700 Subject: [PATCH 04/14] [NFC] Fixup TypeChecker::getOptionalType To Not Return Type() --- lib/Sema/CSGen.cpp | 3 ++- lib/Sema/CSSimplify.cpp | 1 + lib/Sema/TypeCheckType.cpp | 27 ++++++++++++++------------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 376baa96168a0..77808245beacd 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2404,6 +2404,7 @@ namespace { } varType = TypeChecker::getOptionalType(var->getLoc(), varType); + assert(!varType->hasError()); if (oneWayVarType) { oneWayVarType = @@ -3304,7 +3305,7 @@ namespace { /// worth QoI efforts. Type getOptionalType(SourceLoc optLoc, Type valueTy) { auto optTy = TypeChecker::getOptionalType(optLoc, valueTy); - if (!optTy || + if (optTy->hasError() || TypeChecker::requireOptionalIntrinsics(CS.getASTContext(), optLoc)) return Type(); diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 37e2639ccf9a3..179b270d9ee7f 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -6889,6 +6889,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint( TVO_CanBindToLValue | TVO_CanBindToNoEscape); Type optTy = TypeChecker::getOptionalType(SourceLoc(), innerTV); + assert(!optTy->hasError()); SmallVector optionalities; auto nonoptionalResult = Constraint::createFixed( *this, ConstraintKind::Bind, diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 09c6dd091721d..b6112ed488088 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -374,7 +374,7 @@ Type TypeChecker::getOptionalType(SourceLoc loc, Type elementType) { ASTContext &ctx = elementType->getASTContext(); if (!ctx.getOptionalDecl()) { ctx.Diags.diagnose(loc, diag::sugar_type_not_found, 1); - return Type(); + return ErrorType::get(ctx); } return OptionalType::get(elementType); @@ -3342,14 +3342,16 @@ Type TypeResolver::resolveOptionalType(OptionalTypeRepr *repr, TypeResolutionOptions elementOptions = options.withoutContext(true); elementOptions.setContext(TypeResolverContext::ImmediateOptionalTypeArgument); - // The T in T? is a generic type argument and therefore always an AST type. - // FIXME: diagnose non-materializability of element type! Type baseTy = resolveType(repr->getBase(), elementOptions); - if (!baseTy || baseTy->hasError()) return baseTy; + if (!baseTy || baseTy->hasError()) { + return ErrorType::get(Context); + } auto optionalTy = TypeChecker::getOptionalType(repr->getQuestionLoc(), baseTy); - if (!optionalTy) return ErrorType::get(Context); + if (optionalTy->hasError()) { + return ErrorType::get(Context); + } return optionalTy; } @@ -3412,17 +3414,16 @@ Type TypeResolver::resolveImplicitlyUnwrappedOptionalType( TypeResolutionOptions elementOptions = options.withoutContext(true); elementOptions.setContext(TypeResolverContext::ImmediateOptionalTypeArgument); - // The T in T! is a generic type argument and therefore always an AST type. - // FIXME: diagnose non-materializability of element type! Type baseTy = resolveType(repr->getBase(), elementOptions); - if (!baseTy || baseTy->hasError()) return baseTy; - - Type uncheckedOptionalTy; - uncheckedOptionalTy = TypeChecker::getOptionalType(repr->getExclamationLoc(), - baseTy); + if (!baseTy || baseTy->hasError()) { + return ErrorType::get(Context); + } - if (!uncheckedOptionalTy) + Type uncheckedOptionalTy = + TypeChecker::getOptionalType(repr->getExclamationLoc(), baseTy); + if (uncheckedOptionalTy->hasError()) { return ErrorType::get(Context); + } return uncheckedOptionalTy; } From 743230e1693bff536612b96ee9c4851ae4cae7de Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 11:29:10 -0700 Subject: [PATCH 05/14] [NFC] applyGenericArguments Returns ErrorType Consistently --- lib/Sema/TypeCheckType.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index b6112ed488088..093404e7c66a8 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -120,7 +120,7 @@ GenericSignature TypeResolution::getGenericSignature() const { return dc->getGenericSignatureOfContext(); case TypeResolutionStage::Structural: - return nullptr; + return GenericSignature(); } llvm_unreachable("unhandled stage"); } @@ -781,8 +781,9 @@ static Type applyGenericArguments(Type type, TypeResolution resolution, if (nominal->isOptionalDecl()) { // Validate the generic argument. Type objectType = resolution.resolveType(genericArgs[0]); - if (!objectType || objectType->hasError()) - return nullptr; + if (!objectType || objectType->hasError()) { + return ErrorType::get(ctx); + } return BoundGenericType::get(nominal, /*parent*/ Type(), objectType); } @@ -3205,7 +3206,9 @@ Type TypeResolver::resolveIdentifierType(IdentTypeRepr *IdType, ComponentRange.end()); Type result = resolveIdentTypeComponent(resolution.withOptions(options), Components); - if (!result) return nullptr; + if (!result || result->hasError()) { + return ErrorType::get(Context); + } if (auto moduleTy = result->getAs()) { // Allow module types only if flag is specified. From 26ee5d534e0f9cac181583077d3081dfa5a200cf Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 11:30:45 -0700 Subject: [PATCH 06/14] [NFC] Fixup resolveSILFunctionType To Not Return Type() --- lib/Sema/TypeCheckType.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 093404e7c66a8..73f5a0415bcbb 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -2857,9 +2857,8 @@ Type TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, elementOptions.setContext(TypeResolverContext::FunctionInput); auto param = resolveSILParameter(elt.Type, elementOptions); params.push_back(param); - if (!param.getInterfaceType()) return nullptr; - if (param.getInterfaceType()->hasError()) + if (!param.getInterfaceType() || param.getInterfaceType()->hasError()) hasError = true; } From 69dc77f7fe924cb01716b96c4ffbaf33e77c18c5 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 11:34:22 -0700 Subject: [PATCH 07/14] [NFC] Refactor resolveASTFunctionTypeParams Directly return the parameter vector, and handle missing types the same way we handle error types. --- lib/Sema/TypeCheckType.cpp | 39 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 73f5a0415bcbb..0c08804d89810 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1725,12 +1725,9 @@ namespace { = nullptr, DifferentiabilityKind diffKind = DifferentiabilityKind::NonDifferentiable); - bool - resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr, - TypeResolutionOptions options, - bool requiresMappingOut, - DifferentiabilityKind diffKind, - SmallVectorImpl &ps); + SmallVector resolveASTFunctionTypeParams( + TupleTypeRepr *inputRepr, TypeResolutionOptions options, + bool requiresMappingOut, DifferentiabilityKind diffKind); Type resolveSILFunctionType(FunctionTypeRepr *repr, TypeResolutionOptions options, @@ -2453,10 +2450,12 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, return ty; } -bool TypeResolver::resolveASTFunctionTypeParams( - TupleTypeRepr *inputRepr, TypeResolutionOptions options, - bool requiresMappingOut, DifferentiabilityKind diffKind, - SmallVectorImpl &elements) { +SmallVector +TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr, + TypeResolutionOptions options, + bool requiresMappingOut, + DifferentiabilityKind diffKind) { + SmallVector elements; elements.reserve(inputRepr->getNumElements()); auto elementOptions = options.withoutContext(true); @@ -2477,9 +2476,7 @@ bool TypeResolver::resolveASTFunctionTypeParams( } Type ty = resolveType(eltTypeRepr, thisElementOptions); - if (!ty) return true; - - if (ty->hasError()) { + if (!ty || ty->hasError()) { elements.emplace_back(ErrorType::get(Context)); continue; } @@ -2573,7 +2570,7 @@ bool TypeResolver::resolveASTFunctionTypeParams( } } - return false; + return elements; } Type TypeResolver::resolveOpaqueReturnType(TypeRepr *repr, @@ -2626,18 +2623,16 @@ Type TypeResolver::resolveASTFunctionType( TypeResolutionOptions options = None; options |= parentOptions.withoutContext().getFlags(); - - SmallVector params; - if (resolveASTFunctionTypeParams(repr->getArgsTypeRepr(), options, - repr->getGenericEnvironment() != nullptr, - diffKind, params)) { - return Type(); - } + auto params = resolveASTFunctionTypeParams( + repr->getArgsTypeRepr(), options, + repr->getGenericEnvironment() != nullptr, diffKind); auto resultOptions = options.withoutContext(); resultOptions.setContext(TypeResolverContext::FunctionResult); Type outputTy = resolveType(repr->getResultTypeRepr(), resultOptions); - if (!outputTy || outputTy->hasError()) return outputTy; + if (!outputTy || outputTy->hasError()) { + return ErrorType::get(Context); + } // If this is a function type without parens around the parameter list, // diagnose this and produce a fixit to add them. From b6143c62a8265b1ca0e335cf34c8055cfdcbdaaf Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 11:48:27 -0700 Subject: [PATCH 08/14] [NFC] Remove TypeChecker::getIntType Inline it into its only caller --- lib/Sema/CSApply.cpp | 2 +- lib/Sema/TypeCheckType.cpp | 7 ------- lib/Sema/TypeChecker.h | 1 - 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index b7d81bf2caa5d..92648cb78aa6a 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2488,7 +2488,7 @@ namespace { // Make the integer literals for the parameters. auto buildExprFromUnsigned = [&](unsigned value) { LiteralExpr *expr = IntegerLiteralExpr::createFromUnsigned(ctx, value); - cs.setType(expr, TypeChecker::getIntType(ctx)); + cs.setType(expr, ctx.getIntDecl()->getDeclaredInterfaceType()); return handleIntegerLiteralExpr(expr); }; diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 0c08804d89810..5ebe17e0d3094 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -394,13 +394,6 @@ Type TypeChecker::getSubstringType(ASTContext &Context) { return Type(); } -Type TypeChecker::getIntType(ASTContext &Context) { - if (auto typeDecl = Context.getIntDecl()) - return typeDecl->getDeclaredInterfaceType(); - - return Type(); -} - Type TypeChecker::getInt8Type(ASTContext &Context) { if (auto typeDecl = Context.getInt8Decl()) return typeDecl->getDeclaredInterfaceType(); diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 2cb71edf98274..1fecda02df67c 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -348,7 +348,6 @@ Type getArraySliceType(SourceLoc loc, Type elementType); Type getOptionalType(SourceLoc loc, Type elementType); Type getStringType(ASTContext &ctx); Type getSubstringType(ASTContext &ctx); -Type getIntType(ASTContext &ctx); Type getInt8Type(ASTContext &ctx); Type getUInt8Type(ASTContext &ctx); From f02a0f0439edaaeb2b321406f553bab0da5797be Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 11:49:32 -0700 Subject: [PATCH 09/14] [NFC] Remove TypeChecker::getSubstringType Inline it into its only caller --- lib/Sema/CSDiagnostics.cpp | 5 +---- lib/Sema/TypeCheckType.cpp | 4 ---- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index f83ffed73fc32..648308fb6e746 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -2571,10 +2571,7 @@ bool ContextualFailure::trySequenceSubsequenceFixIts( return false; auto String = TypeChecker::getStringType(getASTContext()); - auto Substring = TypeChecker::getSubstringType(getASTContext()); - - if (!String || !Substring) - return false; + auto Substring = getASTContext().getSubstringDecl()->getDeclaredInterfaceType(); // Substring -> String conversion // Wrap in String.init diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 5ebe17e0d3094..2c0b8f8a3248d 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -387,10 +387,6 @@ Type TypeChecker::getStringType(ASTContext &Context) { return Type(); } -Type TypeChecker::getSubstringType(ASTContext &Context) { - if (auto typeDecl = Context.getSubstringDecl()) - return typeDecl->getDeclaredInterfaceType(); - return Type(); } From 09395ba345bbe06c7d0a4f4a13f905d4c1dcc1bf Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 11:52:17 -0700 Subject: [PATCH 10/14] [NFC] Inline TypeChecker::getInt8Type and TypeChecker::getUInt8Type --- lib/Sema/CSSimplify.cpp | 8 ++++---- lib/Sema/TypeCheckType.cpp | 16 +--------------- lib/Sema/TypeChecker.h | 2 -- 3 files changed, 5 insertions(+), 21 deletions(-) diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 179b270d9ee7f..a534d8fed3166 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -2426,9 +2426,9 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2, static bool isStringCompatiblePointerBaseType(ASTContext &ctx, Type baseType) { // Allow strings to be passed to pointer-to-byte or pointer-to-void types. - if (baseType->isEqual(TypeChecker::getInt8Type(ctx))) + if (baseType->isEqual(ctx.getInt8Decl()->getDeclaredInterfaceType())) return true; - if (baseType->isEqual(TypeChecker::getUInt8Type(ctx))) + if (baseType->isEqual(ctx.getUInt8Decl()->getDeclaredInterfaceType())) return true; if (baseType->isEqual(ctx.TheEmptyTupleType)) return true; @@ -9213,11 +9213,11 @@ ConstraintSystem::simplifyRestrictedConstraintImpl( auto &ctx = getASTContext(); auto int8Con = Constraint::create(*this, ConstraintKind::Bind, baseType2, - TypeChecker::getInt8Type(ctx), + ctx.getInt8Decl()->getDeclaredInterfaceType(), getConstraintLocator(locator)); auto uint8Con = Constraint::create(*this, ConstraintKind::Bind, baseType2, - TypeChecker::getUInt8Type(ctx), + ctx.getUInt8Decl()->getDeclaredInterfaceType(), getConstraintLocator(locator)); auto voidCon = Constraint::create(*this, ConstraintKind::Bind, baseType2, ctx.TheEmptyTupleType, diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 2c0b8f8a3248d..f5a2c3d8c0d12 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -386,21 +386,7 @@ Type TypeChecker::getStringType(ASTContext &Context) { return Type(); } - - return Type(); -} - -Type TypeChecker::getInt8Type(ASTContext &Context) { - if (auto typeDecl = Context.getInt8Decl()) - return typeDecl->getDeclaredInterfaceType(); - - return Type(); -} - -Type TypeChecker::getUInt8Type(ASTContext &Context) { - if (auto typeDecl = Context.getUInt8Decl()) - return typeDecl->getDeclaredInterfaceType(); - + llvm::report_fatal_error("Broken Standard library: Cannot resolve String"); return Type(); } diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 1fecda02df67c..68f83dd0b774d 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -348,8 +348,6 @@ Type getArraySliceType(SourceLoc loc, Type elementType); Type getOptionalType(SourceLoc loc, Type elementType); Type getStringType(ASTContext &ctx); Type getSubstringType(ASTContext &ctx); -Type getInt8Type(ASTContext &ctx); -Type getUInt8Type(ASTContext &ctx); /// Bind an UnresolvedDeclRefExpr by performing name lookup and /// returning the resultant expression. Context is the DeclContext used From 399a5510d21d7e9d272505e40ad3df714030cc93 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 11:54:21 -0700 Subject: [PATCH 11/14] [NFC] Inline TypeChecker::getStringType --- lib/Sema/CSApply.cpp | 4 +++- lib/Sema/CSDiagnostics.cpp | 2 +- lib/Sema/CSSimplify.cpp | 3 ++- lib/Sema/TypeCheckType.cpp | 10 ---------- lib/Sema/TypeChecker.h | 2 -- 5 files changed, 6 insertions(+), 15 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 92648cb78aa6a..766c57bc496f1 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -4698,7 +4698,9 @@ namespace { StringRef(stringCopy, compatStringBuf.size()), SourceRange(), /*implicit*/ true); - cs.setType(stringExpr, TypeChecker::getStringType(cs.getASTContext())); + cs.setType( + stringExpr, + cs.getASTContext().getStringDecl()->getDeclaredInterfaceType()); E->setObjCStringLiteralExpr(stringExpr); } } diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 648308fb6e746..1e455b9a25dc6 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -2570,7 +2570,7 @@ bool ContextualFailure::trySequenceSubsequenceFixIts( if (!getASTContext().getStdlibModule()) return false; - auto String = TypeChecker::getStringType(getASTContext()); + auto String = getASTContext().getStringDecl()->getDeclaredInterfaceType(); auto Substring = getASTContext().getSubstringDecl()->getDeclaredInterfaceType(); // Substring -> String conversion diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index a534d8fed3166..50e3b0ef2ed21 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -4926,7 +4926,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind, // The pointer can be converted from a string, if the element // type is compatible. auto &ctx = getASTContext(); - if (type1->isEqual(TypeChecker::getStringType(ctx))) { + if (type1->isEqual( + ctx.getStringDecl()->getDeclaredInterfaceType())) { auto baseTy = getFixedTypeRecursive(pointeeTy, false); if (baseTy->isTypeVariableOrMember() || diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index f5a2c3d8c0d12..39701fafc2fc8 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -380,16 +380,6 @@ Type TypeChecker::getOptionalType(SourceLoc loc, Type elementType) { return OptionalType::get(elementType); } -Type TypeChecker::getStringType(ASTContext &Context) { - if (auto typeDecl = Context.getStringDecl()) - return typeDecl->getDeclaredInterfaceType(); - - return Type(); -} - llvm::report_fatal_error("Broken Standard library: Cannot resolve String"); - return Type(); -} - Type TypeChecker::getDynamicBridgedThroughObjCClass(DeclContext *dc, Type dynamicType, diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index 68f83dd0b774d..7315910400fff 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -346,8 +346,6 @@ enum class CheckedCastContextKind { namespace TypeChecker { Type getArraySliceType(SourceLoc loc, Type elementType); Type getOptionalType(SourceLoc loc, Type elementType); -Type getStringType(ASTContext &ctx); -Type getSubstringType(ASTContext &ctx); /// Bind an UnresolvedDeclRefExpr by performing name lookup and /// returning the resultant expression. Context is the DeclContext used From eacc130999f7163df5a7f3669bdfa0bc88629f6e Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 11:56:11 -0700 Subject: [PATCH 12/14] [NFC] Consistently return ErrorTypes when resolveType fails --- lib/Sema/TypeCheckType.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 39701fafc2fc8..cbf73d6c55a9c 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -3530,7 +3530,9 @@ Type TypeResolver::resolveMetatypeType(MetatypeTypeRepr *repr, TypeResolutionOptions options) { // The instance type of a metatype is always abstract, not SIL-lowered. Type ty = resolveType(repr->getBase(), options.withoutContext()); - if (!ty || ty->hasError()) return ty; + if (!ty || ty->hasError()) { + return ErrorType::get(Context); + } Optional storedRepr; @@ -3561,7 +3563,9 @@ Type TypeResolver::resolveProtocolType(ProtocolTypeRepr *repr, TypeResolutionOptions options) { // The instance type of a metatype is always abstract, not SIL-lowered. Type ty = resolveType(repr->getBase(), options.withoutContext()); - if (!ty || ty->hasError()) return ty; + if (!ty || ty->hasError()) { + return ErrorType::get(Context); + } Optional storedRepr; From 6ab29cbe4e973779baebefdf0318c894764a72aa Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 13:00:21 -0700 Subject: [PATCH 13/14] Introduce NeverNullType to Assert resolveType Never Returns the null Type --- lib/Sema/TypeCheckType.cpp | 89 ++++++++++++------- .../0163-sr8033.swift | 2 +- 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index cbf73d6c55a9c..92d38f57dc98e 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -1647,6 +1647,34 @@ namespace { const auto DefaultParameterConvention = ParameterConvention::Direct_Unowned; const auto DefaultResultConvention = ResultConvention::Unowned; + /// A wrapper that ensures that the returned type from + /// \c TypeResolver::resolveType is never the null \c Type. It otherwise + /// tries to behave like \c Type, so it provides the proper conversion and + /// arrow operators. + class NeverNullType final { + public: + /// Forbid default construction. + NeverNullType() = delete; + /// Forbid construction from \c nullptr. + NeverNullType(std::nullptr_t) = delete; + + public: + /// Construct a never-null Type. If \p Ty is null, a fatal error is thrown. + NeverNullType(Type Ty) : WrappedTy(Ty) { + if (Ty.isNull()) { + llvm::report_fatal_error("Resolved to null type!"); + } + } + + operator Type() const { return WrappedTy; } + Type get() const { return WrappedTy; } + + TypeBase *operator->() const { return WrappedTy.operator->(); } + + private: + Type WrappedTy; + }; + class TypeResolver { ASTContext &Context; TypeResolution resolution; @@ -1660,7 +1688,7 @@ namespace { { } - Type resolveType(TypeRepr *repr, TypeResolutionOptions options); + NeverNullType resolveType(TypeRepr *repr, TypeResolutionOptions options); private: template @@ -1795,7 +1823,8 @@ Type ResolveTypeRequest::evaluate(Evaluator &evaluator, return result; } -Type TypeResolver::resolveType(TypeRepr *repr, TypeResolutionOptions options) { +NeverNullType TypeResolver::resolveType(TypeRepr *repr, + TypeResolutionOptions options) { assert(repr && "Cannot validate null TypeReprs!"); // If we know the type representation is invalid, just return an @@ -1891,9 +1920,9 @@ Type TypeResolver::resolveType(TypeRepr *repr, TypeResolutionOptions options) { options |= TypeResolutionFlags::SilenceErrors; auto constraintType = resolveType(opaqueRepr->getConstraint(), options); - - return constraintType && !constraintType->hasError() - ? ErrorType::get(constraintType) : ErrorType::get(Context); + + return !constraintType->hasError() ? ErrorType::get(constraintType) + : ErrorType::get(Context); } case TypeReprKind::Fixed: @@ -1976,7 +2005,7 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs, instanceOptions -= TypeResolutionFlags::SILType; auto instanceTy = resolveType(base, instanceOptions); - if (!instanceTy || instanceTy->hasError()) + if (instanceTy->hasError()) return instanceTy; // Check for @thin. @@ -2440,8 +2469,8 @@ TypeResolver::resolveASTFunctionTypeParams(TupleTypeRepr *inputRepr, variadic = true; } - Type ty = resolveType(eltTypeRepr, thisElementOptions); - if (!ty || ty->hasError()) { + auto ty = resolveType(eltTypeRepr, thisElementOptions); + if (ty->hasError()) { elements.emplace_back(ErrorType::get(Context)); continue; } @@ -2550,7 +2579,7 @@ Type TypeResolver::resolveOpaqueReturnType(TypeRepr *repr, for (auto argRepr : generic->getGenericArgs()) { auto argTy = resolveType(argRepr, options); // If we cannot resolve the generic parameter, propagate the error out. - if (!argTy || argTy->hasError()) { + if (argTy->hasError()) { return ErrorType::get(Context); } TypeArgsBuf.push_back(argTy); @@ -2594,8 +2623,8 @@ Type TypeResolver::resolveASTFunctionType( auto resultOptions = options.withoutContext(); resultOptions.setContext(TypeResolverContext::FunctionResult); - Type outputTy = resolveType(repr->getResultTypeRepr(), resultOptions); - if (!outputTy || outputTy->hasError()) { + auto outputTy = resolveType(repr->getResultTypeRepr(), resultOptions); + if (outputTy->hasError()) { return ErrorType::get(Context); } @@ -3255,8 +3284,8 @@ Type TypeResolver::resolveSpecifierTypeRepr(SpecifierTypeRepr *repr, Type TypeResolver::resolveArrayType(ArrayTypeRepr *repr, TypeResolutionOptions options) { - Type baseTy = resolveType(repr->getBase(), options.withoutContext()); - if (!baseTy || baseTy->hasError()) { + auto baseTy = resolveType(repr->getBase(), options.withoutContext()); + if (baseTy->hasError()) { return ErrorType::get(Context); } @@ -3272,13 +3301,13 @@ Type TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr, TypeResolutionOptions options) { options = adjustOptionsForGenericArgs(options); - Type keyTy = resolveType(repr->getKey(), options.withoutContext()); - if (!keyTy || keyTy->hasError()) { + auto keyTy = resolveType(repr->getKey(), options.withoutContext()); + if (keyTy->hasError()) { return ErrorType::get(Context); } - Type valueTy = resolveType(repr->getValue(), options.withoutContext()); - if (!valueTy || valueTy->hasError()) { + auto valueTy = resolveType(repr->getValue(), options.withoutContext()); + if (valueTy->hasError()) { return ErrorType::get(Context); } @@ -3304,8 +3333,8 @@ Type TypeResolver::resolveOptionalType(OptionalTypeRepr *repr, TypeResolutionOptions elementOptions = options.withoutContext(true); elementOptions.setContext(TypeResolverContext::ImmediateOptionalTypeArgument); - Type baseTy = resolveType(repr->getBase(), elementOptions); - if (!baseTy || baseTy->hasError()) { + auto baseTy = resolveType(repr->getBase(), elementOptions); + if (baseTy->hasError()) { return ErrorType::get(Context); } @@ -3376,12 +3405,12 @@ Type TypeResolver::resolveImplicitlyUnwrappedOptionalType( TypeResolutionOptions elementOptions = options.withoutContext(true); elementOptions.setContext(TypeResolverContext::ImmediateOptionalTypeArgument); - Type baseTy = resolveType(repr->getBase(), elementOptions); - if (!baseTy || baseTy->hasError()) { + auto baseTy = resolveType(repr->getBase(), elementOptions); + if (baseTy->hasError()) { return ErrorType::get(Context); } - Type uncheckedOptionalTy = + auto uncheckedOptionalTy = TypeChecker::getOptionalType(repr->getExclamationLoc(), baseTy); if (uncheckedOptionalTy->hasError()) { return ErrorType::get(Context); @@ -3416,8 +3445,8 @@ Type TypeResolver::resolveTupleType(TupleTypeRepr *repr, for (unsigned i = 0, end = repr->getNumElements(); i != end; ++i) { auto *tyR = repr->getElementType(i); - Type ty = resolveType(tyR, elementOptions); - if (!ty || ty->hasError()) + auto ty = resolveType(tyR, elementOptions); + if (ty->hasError()) hadError = true; auto eltName = repr->getElementName(i); @@ -3485,8 +3514,8 @@ Type TypeResolver::resolveCompositionType(CompositionTypeRepr *repr, }; for (auto tyR : repr->getTypes()) { - Type ty = resolveType(tyR, options.withoutContext()); - if (!ty || ty->hasError()) return ty; + auto ty = resolveType(tyR, options.withoutContext()); + if (ty->hasError()) return ty; auto nominalDecl = ty->getAnyNominal(); if (nominalDecl && isa(nominalDecl)) { @@ -3529,8 +3558,8 @@ Type TypeResolver::resolveCompositionType(CompositionTypeRepr *repr, Type TypeResolver::resolveMetatypeType(MetatypeTypeRepr *repr, TypeResolutionOptions options) { // The instance type of a metatype is always abstract, not SIL-lowered. - Type ty = resolveType(repr->getBase(), options.withoutContext()); - if (!ty || ty->hasError()) { + auto ty = resolveType(repr->getBase(), options.withoutContext()); + if (ty->hasError()) { return ErrorType::get(Context); } @@ -3562,8 +3591,8 @@ Type TypeResolver::buildMetatypeType( Type TypeResolver::resolveProtocolType(ProtocolTypeRepr *repr, TypeResolutionOptions options) { // The instance type of a metatype is always abstract, not SIL-lowered. - Type ty = resolveType(repr->getBase(), options.withoutContext()); - if (!ty || ty->hasError()) { + auto ty = resolveType(repr->getBase(), options.withoutContext()); + if (ty->hasError()) { return ErrorType::get(Context); } diff --git a/validation-test/compiler_crashers_2_fixed/0163-sr8033.swift b/validation-test/compiler_crashers_2_fixed/0163-sr8033.swift index 3553340caf55c..cd51bdf472be7 100644 --- a/validation-test/compiler_crashers_2_fixed/0163-sr8033.swift +++ b/validation-test/compiler_crashers_2_fixed/0163-sr8033.swift @@ -7,4 +7,4 @@ protocol P1 { } extension Foo: P1 where A : P1 {} // expected-error {{unsupported recursion for reference to associated type 'A' of type 'Foo'}} // expected-error@-1 {{type 'Foo' does not conform to protocol 'P1'}} -// expected-error@-2 {{type 'Foo' in conformance requirement does not refer to a generic parameter or associated type}} +// expected-error@-2 {{type '<>' in conformance requirement does not refer to a generic parameter or associated type}} From 002369565b9ab3052c352046fe59c6e0155d5184 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 11 Jun 2020 13:04:53 -0700 Subject: [PATCH 14/14] [NFC] Update calls to assume resolveType never returns null --- lib/Sema/CSGen.cpp | 4 ++-- lib/Sema/TypeCheckAttr.cpp | 2 +- lib/Sema/TypeCheckConstraints.cpp | 2 +- lib/Sema/TypeCheckPattern.cpp | 4 ++-- lib/Sema/TypeCheckType.cpp | 2 +- lib/Sema/TypeCheckType.h | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 77808245beacd..356833955c0df 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1499,7 +1499,7 @@ namespace { options |= TypeResolutionFlags::AllowUnboundGenerics; auto result = TypeResolution::forContextual(CS.DC, options) .resolveType(repr); - if (!result || result->hasError()) { + if (result->hasError()) { return Type(); } return result; @@ -2771,7 +2771,7 @@ namespace { Type castType = TypeResolution::forContextual( CS.DC, TypeResolverContext::InExpression) .resolveType(isp->getCastTypeRepr()); - if (!castType) { + if (castType->hasError()) { return false; } diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 505232f6748ad..77bdb991f794d 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2853,7 +2853,7 @@ void AttributeChecker::visitImplementsAttr(ImplementsAttr *attr) { } // Definite error-types were already diagnosed in resolveType. - if (!T || T->hasError()) + if (T->hasError()) return; attr->setProtocolType(T); diff --git a/lib/Sema/TypeCheckConstraints.cpp b/lib/Sema/TypeCheckConstraints.cpp index 7435775298de8..3aec9a838eacb 100644 --- a/lib/Sema/TypeCheckConstraints.cpp +++ b/lib/Sema/TypeCheckConstraints.cpp @@ -1397,7 +1397,7 @@ TypeExpr *PreCheckExpression::simplifyNestedTypeExpr(UnresolvedDotExpr *UDE) { auto resolution = TypeResolution::forContextual(DC, options); auto BaseTy = resolution.resolveType(InnerTypeRepr); - if (BaseTy && BaseTy->mayHaveMembers()) { + if (BaseTy->mayHaveMembers()) { auto lookupOptions = defaultMemberLookupOptions; if (isa(DC) || isa(DC)) diff --git a/lib/Sema/TypeCheckPattern.cpp b/lib/Sema/TypeCheckPattern.cpp index 3cee1b6d1ce01..f24f3df0c0c0e 100644 --- a/lib/Sema/TypeCheckPattern.cpp +++ b/lib/Sema/TypeCheckPattern.cpp @@ -705,7 +705,7 @@ static Type validateTypedPattern(TypedPattern *TP, TypeResolution resolution) { } auto ty = resolution.resolveType(Repr); - if (!ty || ty->hasError()) { + if (ty->hasError()) { return ErrorType::get(Context); } @@ -1233,7 +1233,7 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern, TypeResolutionOptions paramOptions(TypeResolverContext::InExpression); auto castType = TypeResolution::forContextual(dc, paramOptions) .resolveType(IP->getCastTypeRepr()); - if (!castType || castType->hasError()) + if (castType->hasError()) return nullptr; IP->setCastType(castType); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 92d38f57dc98e..ca1c584062354 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -746,7 +746,7 @@ static Type applyGenericArguments(Type type, TypeResolution resolution, if (nominal->isOptionalDecl()) { // Validate the generic argument. Type objectType = resolution.resolveType(genericArgs[0]); - if (!objectType || objectType->hasError()) { + if (objectType->hasError()) { return ErrorType::get(ctx); } diff --git a/lib/Sema/TypeCheckType.h b/lib/Sema/TypeCheckType.h index b09e418464c2a..e32632d877330 100644 --- a/lib/Sema/TypeCheckType.h +++ b/lib/Sema/TypeCheckType.h @@ -366,7 +366,7 @@ class TypeResolution { /// /// \param TyR The type representation to check. /// - /// \returns a well-formed type or an ErrorType in case of an error. + /// \returns A well-formed type that is never null, or an \c ErrorType in case of an error. Type resolveType(TypeRepr *TyR); /// Whether this type resolution uses archetypes (vs. generic parameters).