diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index a09cc177bb261..9d5fcde30fe74 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -225,6 +225,13 @@ ERROR(cannot_apply_lvalue_binop_to_subelement,none, ERROR(cannot_apply_lvalue_binop_to_rvalue,none, "left side of mutating operator has immutable type %0", (Type)) +ERROR(cannot_subscript_base,none, + "cannot subscript a value of type %0", + (Type)) + +ERROR(cannot_subscript_ambiguous_base,none, + "cannot subscript a value of incorrect or ambiguous type", ()) + ERROR(cannot_subscript_nil_literal,none, "cannot subscript a nil literal value", ()) ERROR(conditional_cast_from_nil,none, diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index c04b3a7d95ac2..c553390f1800b 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -3148,9 +3148,24 @@ class LoadExpr : public ImplicitConversionExpr { static bool classof(const Expr *E) { return E->getKind() == ExprKind::Load; } }; +/// This is a conversion from an expression of UnresolvedType to an arbitrary +/// other type, and from an arbitrary type to UnresolvedType. This node does +/// not appear in valid code, only in code involving diagnostics. +class UnresolvedTypeConversionExpr : public ImplicitConversionExpr { +public: + UnresolvedTypeConversionExpr(Expr *subExpr, Type type) + : ImplicitConversionExpr(ExprKind::UnresolvedTypeConversion, subExpr, type) {} + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::UnresolvedTypeConversion; + } +}; + /// FunctionConversionExpr - Convert a function to another function type, /// which might involve renaming the parameters or handling substitutions /// of subtypes (in the return) or supertypes (in the input). +/// +/// FIXME: This should be a CapturingExpr. class FunctionConversionExpr : public ImplicitConversionExpr { public: FunctionConversionExpr(Expr *subExpr, Type type) diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index 7ec7439d25585..37bb244147cc0 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -151,6 +151,7 @@ ABSTRACT_EXPR(Apply, Expr) ABSTRACT_EXPR(ImplicitConversion, Expr) EXPR(Load, ImplicitConversionExpr) EXPR(DestructureTuple, ImplicitConversionExpr) + EXPR(UnresolvedTypeConversion, ImplicitConversionExpr) EXPR(FunctionConversion, ImplicitConversionExpr) EXPR(CovariantFunctionConversion, ImplicitConversionExpr) EXPR(CovariantReturnConversion, ImplicitConversionExpr) diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 2ca611409d434..c399c72a23867 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -2270,6 +2270,11 @@ class PrintExpr : public ExprVisitor { printRec(E->getResultExpr()); PrintWithColorRAII(OS, ParenthesisColor) << ')'; } + void visitUnresolvedTypeConversionExpr(UnresolvedTypeConversionExpr *E) { + printCommon(E, "unresolvedtype_conversion_expr") << '\n'; + printRec(E->getSubExpr()); + PrintWithColorRAII(OS, ParenthesisColor) << ')'; + } void visitFunctionConversionExpr(FunctionConversionExpr *E) { printCommon(E, "function_conversion_expr") << '\n'; printRec(E->getSubExpr()); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index c1abf42881ed6..10fec931e365c 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -338,6 +338,7 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const { PASS_THROUGH_REFERENCE(Load, getSubExpr); NO_REFERENCE(DestructureTuple); + NO_REFERENCE(UnresolvedTypeConversion); PASS_THROUGH_REFERENCE(FunctionConversion, getSubExpr); PASS_THROUGH_REFERENCE(CovariantFunctionConversion, getSubExpr); PASS_THROUGH_REFERENCE(CovariantReturnConversion, getSubExpr); @@ -662,6 +663,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const { case ExprKind::Load: case ExprKind::DestructureTuple: + case ExprKind::UnresolvedTypeConversion: case ExprKind::FunctionConversion: case ExprKind::CovariantFunctionConversion: case ExprKind::CovariantReturnConversion: diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index c5626c9288a46..c4adcbf7e63b3 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -446,6 +446,8 @@ namespace { RValue visitConditionalBridgeFromObjCExpr(ConditionalBridgeFromObjCExpr *E, SGFContext C); RValue visitArchetypeToSuperExpr(ArchetypeToSuperExpr *E, SGFContext C); + RValue visitUnresolvedTypeConversionExpr(UnresolvedTypeConversionExpr *E, + SGFContext C); RValue visitFunctionConversionExpr(FunctionConversionExpr *E, SGFContext C); RValue visitCovariantFunctionConversionExpr( @@ -956,6 +958,12 @@ RValue RValueEmitter::visitSuperRefExpr(SuperRefExpr *E, SGFContext C) { return RValue(SGF, E, result); } +RValue RValueEmitter:: +visitUnresolvedTypeConversionExpr(UnresolvedTypeConversionExpr *E, + SGFContext C) { + llvm_unreachable("invalid code made its way into SILGen"); +} + RValue RValueEmitter::visitOtherConstructorDeclRefExpr( OtherConstructorDeclRefExpr *E, SGFContext C) { // This should always be a child of an ApplyExpr and so will be emitted by diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 387c39025f4cb..a7eb442abeced 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2884,7 +2884,8 @@ namespace { auto type = simplifyType(openedType); cs.setType(expr, type); - assert(!type->is()); + if (type->is()) + return expr; auto &ctx = cs.getASTContext(); @@ -2907,11 +2908,14 @@ namespace { ConcreteDeclRef witness = conformance.getWitnessByName( conformingType->getRValueType(), constrName); - auto selectedOverload = solution.getOverloadChoice( + auto selectedOverload = solution.getOverloadChoiceIfAvailable( cs.getConstraintLocator(expr, ConstraintLocator::ConstructorMember)); + if (!selectedOverload) + return nullptr; + auto fnType = - simplifyType(selectedOverload.openedType)->castTo(); + simplifyType(selectedOverload->openedType)->castTo(); auto newArg = coerceCallArguments( expr->getArg(), fnType, witness, @@ -3211,8 +3215,18 @@ namespace { // Determine the declaration selected for this overloaded reference. auto memberLocator = cs.getConstraintLocator(expr, ConstraintLocator::Member); - auto selected = solution.getOverloadChoice(memberLocator); + auto selectedElt = solution.getOverloadChoiceIfAvailable(memberLocator); + + if (!selectedElt) { + // If constraint solving resolved this to an UnresolvedType, then we're + // in an ambiguity tolerant mode used for diagnostic generation. Just + // leave this as whatever type of member reference it already is. + Type resultTy = simplifyType(cs.getType(expr)); + cs.setType(expr, resultTy); + return expr; + } + auto selected = *selectedElt; if (!selected.choice.getBaseType()) { // This is one of the "outer alternatives", meaning the innermost // methods didn't work out. @@ -3444,19 +3458,40 @@ namespace { Expr *visitSubscriptExpr(SubscriptExpr *expr) { auto *memberLocator = cs.getConstraintLocator(expr, ConstraintLocator::SubscriptMember); - auto overload = solution.getOverloadChoice(memberLocator); + auto overload = solution.getOverloadChoiceIfAvailable(memberLocator); + + // Handles situation where there was a solution available but it didn't + // have a proper overload selected from subscript call, might be because + // solver was allowed to return free or unresolved types, which can + // happen while running diagnostics on one of the expressions. + if (!overload) { + auto *base = expr->getBase(); + auto &de = cs.getASTContext().Diags; + auto baseType = cs.getType(base); - if (overload.choice.getKind() == + if (auto errorType = baseType->getAs()) { + de.diagnose(base->getLoc(), diag::cannot_subscript_base, + errorType->getOriginalType()) + .highlight(base->getSourceRange()); + } else { + de.diagnose(base->getLoc(), diag::cannot_subscript_ambiguous_base) + .highlight(base->getSourceRange()); + } + + return nullptr; + } + + if (overload->choice.getKind() == OverloadChoiceKind::KeyPathDynamicMemberLookup) { return buildDynamicMemberLookupRef( expr, expr->getBase(), expr->getIndex()->getStartLoc(), SourceLoc(), - overload, memberLocator); + *overload, memberLocator); } return buildSubscript( expr->getBase(), expr->getIndex(), expr->getArgumentLabels(), expr->hasTrailingClosure(), cs.getConstraintLocator(expr), - expr->isImplicit(), expr->getAccessSemantics(), overload); + expr->isImplicit(), expr->getAccessSemantics(), *overload); } /// "Finish" an array expression by filling in the semantic expression. @@ -4327,7 +4362,8 @@ namespace { expr->getSubPattern()->forEachVariable([](VarDecl *VD) { VD->setInvalid(); }); - if (!SuppressDiagnostics) { + if (!SuppressDiagnostics + && !cs.getType(simplified)->is()) { auto &de = cs.getASTContext().Diags; de.diagnose(simplified->getLoc(), diag::pattern_in_expr, expr->getSubPattern()->getKind()); @@ -4806,12 +4842,18 @@ namespace { // If this is an unresolved link, make sure we resolved it. if (kind == KeyPathExpr::Component::Kind::UnresolvedProperty || kind == KeyPathExpr::Component::Kind::UnresolvedSubscript) { - auto foundDecl = solution.getOverloadChoice(locator); + auto foundDecl = solution.getOverloadChoiceIfAvailable(locator); + if (!foundDecl) { + // If we couldn't resolve the component, leave it alone. + resolvedComponents.push_back(origComponent); + componentTy = origComponent.getComponentType(); + continue; + } isDynamicMember = - foundDecl.choice.getKind() == + foundDecl->choice.getKind() == OverloadChoiceKind::DynamicMemberLookup || - foundDecl.choice.getKind() == + foundDecl->choice.getKind() == OverloadChoiceKind::KeyPathDynamicMemberLookup; // If this was a @dynamicMemberLookup property, then we actually @@ -4842,9 +4884,11 @@ namespace { case KeyPathExpr::Component::Kind::OptionalChain: { didOptionalChain = true; // Chaining always forces the element to be an rvalue. - assert(!componentTy->hasUnresolvedType()); auto objectTy = componentTy->getWithoutSpecifierType()->getOptionalObjectType(); + if (componentTy->hasUnresolvedType() && !objectTy) { + objectTy = componentTy; + } assert(objectTy); auto loc = origComponent.getLoc(); @@ -4896,8 +4940,8 @@ namespace { } // Wrap a non-optional result if there was chaining involved. - assert(!componentTy->hasUnresolvedType()); if (didOptionalChain && componentTy && + !componentTy->hasUnresolvedType() && !componentTy->getWithoutSpecifierType()->isEqual(leafTy)) { assert(leafTy->getOptionalObjectType()->isEqual( componentTy->getWithoutSpecifierType())); @@ -4916,8 +4960,8 @@ namespace { // The final component type ought to line up with the leaf type of the // key path. - assert(!componentTy->hasUnresolvedType()); - assert(componentTy->getWithoutSpecifierType()->isEqual(leafTy)); + assert(!componentTy || componentTy->hasUnresolvedType() + || componentTy->getWithoutSpecifierType()->isEqual(leafTy)); if (!isFunctionType) return E; @@ -5022,13 +5066,18 @@ namespace { // Unwrap the last component type, preserving @lvalue-ness. auto optionalTy = components.back().getComponentType(); - assert(!optionalTy->hasUnresolvedType()); Type objectTy; if (auto lvalue = optionalTy->getAs()) { objectTy = lvalue->getObjectType()->getOptionalObjectType(); + if (optionalTy->hasUnresolvedType() && !objectTy) { + objectTy = optionalTy; + } objectTy = LValueType::get(objectTy); } else { objectTy = optionalTy->getOptionalObjectType(); + if (optionalTy->hasUnresolvedType() && !objectTy) { + objectTy = optionalTy; + } } assert(objectTy); @@ -5457,9 +5506,11 @@ Expr *ExprRewriter::coerceExistential(Expr *expr, Type toType) { Type toInstanceType = toType; // Look through metatypes - while (fromInstanceType->is() && + while ((fromInstanceType->is() || + fromInstanceType->is()) && toInstanceType->is()) { - fromInstanceType = fromInstanceType->castTo()->getInstanceType(); + if (!fromInstanceType->is()) + fromInstanceType = fromInstanceType->castTo()->getInstanceType(); toInstanceType = toInstanceType->castTo()->getInstanceType(); } @@ -5659,6 +5710,11 @@ Expr *ExprRewriter::coerceCallArguments( LocatorPathElt::ApplyArgToParam(argIdx, paramIdx, flags)); }; + bool matchCanFail = + llvm::any_of(params, [](const AnyFunctionType::Param ¶m) { + return param.getPlainType()->hasUnresolvedType(); + }); + // Determine whether this application has curried self. bool skipCurriedSelf = apply ? hasCurriedSelf(cs, callee, apply) : true; // Determine the parameter bindings. @@ -5716,7 +5772,9 @@ Expr *ExprRewriter::coerceCallArguments( args, params, paramInfo, unlabeledTrailingClosureIndex, /*allowFixes=*/false, listener, trailingClosureMatching); - assert(callArgumentMatch && "Call arguments did not match up?"); + assert((matchCanFail || callArgumentMatch) && + "Call arguments did not match up?"); + (void)matchCanFail; auto parameterBindings = std::move(callArgumentMatch->parameterBindings); @@ -6453,7 +6511,8 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, if (knownRestriction != solution.ConstraintRestrictions.end()) { switch (knownRestriction->second) { case ConversionRestrictionKind::DeepEquality: { - assert(!toType->hasUnresolvedType()); + if (toType->hasUnresolvedType()) + break; // HACK: Fix problem related to Swift 4 mode (with assertions), // since Swift 4 mode allows passing arguments with extra parens @@ -6999,8 +7058,9 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType, break; } - assert(!fromType->hasUnresolvedType()); - assert(!toType->hasUnresolvedType()); + // Unresolved types come up in diagnostics for lvalue and inout types. + if (fromType->hasUnresolvedType() || toType->hasUnresolvedType()) + return cs.cacheType(new (ctx) UnresolvedTypeConversionExpr(expr, toType)); // Use an opaque type to abstract a value of the underlying concrete type. if (toType->getAs()) { @@ -7577,7 +7637,11 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, // FIXME: handle unwrapping everywhere else assert(!unwrapResult); - assert(!cs.getType(fn)->is()); + // If this is an UnresolvedType in the system, preserve it. + if (cs.getType(fn)->is()) { + cs.setType(apply, cs.getType(fn)); + return apply; + } // We have a type constructor. auto metaTy = cs.getType(fn)->castTo(); @@ -7585,6 +7649,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, // If we're "constructing" a tuple type, it's simply a conversion. if (auto tupleTy = ty->getAs()) { + // FIXME: Need an AST to represent this properly. return coerceToType(apply->getArg(), tupleTy, locator); } @@ -7593,14 +7658,19 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType, auto *ctorLocator = cs.getConstraintLocator(locator, {ConstraintLocator::ApplyFunction, ConstraintLocator::ConstructorMember}); - auto selected = solution.getOverloadChoice(ctorLocator); + auto selected = solution.getOverloadChoiceIfAvailable(ctorLocator); + if (!selected) { + assert(ty->hasError() || ty->hasUnresolvedType()); + cs.setType(apply, ty); + return apply; + } assert(ty->getNominalOrBoundGenericNominal() || ty->is() || ty->isExistentialType() || ty->is()); // Consider the constructor decl reference expr 'implicit', but the // constructor call expr itself has the apply's 'implicitness'. - Expr *declRef = buildMemberRef(fn, /*dotLoc=*/SourceLoc(), selected, + Expr *declRef = buildMemberRef(fn, /*dotLoc=*/SourceLoc(), *selected, DeclNameLoc(fn->getEndLoc()), locator, ctorLocator, /*implicit=*/true, AccessSemantics::Ordinary); diff --git a/validation-test/IDE/crashers_2_fixed/rdar75200446.swift b/validation-test/IDE/crashers_2_fixed/rdar75200446.swift new file mode 100644 index 0000000000000..5ab0301500b39 --- /dev/null +++ b/validation-test/IDE/crashers_2_fixed/rdar75200446.swift @@ -0,0 +1,3 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COMPLETE + +.undefined() #^COMPLETE^# diff --git a/validation-test/IDE/crashers_2_fixed/rdar75219757.swift b/validation-test/IDE/crashers_2_fixed/rdar75219757.swift new file mode 100644 index 0000000000000..b3077e4364418 --- /dev/null +++ b/validation-test/IDE/crashers_2_fixed/rdar75219757.swift @@ -0,0 +1,3 @@ +// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COMPLETE + +0odd.foo.bar #^COMPLETE^#