diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 4116e101a4775..4341bc7b0954e 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -4628,8 +4628,6 @@ NOTE(duplicated_key_declared_here, none, // Generic specializations ERROR(cannot_explicitly_specialize_generic_function,none, "cannot explicitly specialize a generic function", ()) -ERROR(not_a_generic_definition,none, - "cannot specialize a non-generic definition", ()) ERROR(not_a_generic_type,none, "cannot specialize non-generic type %0", (Type)) ERROR(protocol_declares_unknown_primary_assoc_type,none, diff --git a/include/swift/Sema/CSFix.h b/include/swift/Sema/CSFix.h index 228454235edfe..2249912c9ef29 100644 --- a/include/swift/Sema/CSFix.h +++ b/include/swift/Sema/CSFix.h @@ -459,9 +459,12 @@ enum class FixKind : uint8_t { /// because its name doesn't appear in 'initializes' or 'accesses' attributes. AllowInvalidMemberReferenceInInitAccessor, - /// Ignore an attempt to specialize non-generic type. + /// Ignore an attempt to specialize a non-generic type. AllowConcreteTypeSpecialization, + /// Ignore an attempt to specialize a generic function. + AllowGenericFunctionSpecialization, + /// Ignore an out-of-place \c then statement. IgnoreOutOfPlaceThenStmt, @@ -3713,6 +3716,33 @@ class AllowConcreteTypeSpecialization final : public ConstraintFix { } }; +class AllowGenericFunctionSpecialization final : public ConstraintFix { + ValueDecl *Decl; + + AllowGenericFunctionSpecialization(ConstraintSystem &cs, ValueDecl *decl, + ConstraintLocator *locator) + : ConstraintFix(cs, FixKind::AllowConcreteTypeSpecialization, locator), + Decl(decl) {} + +public: + std::string getName() const override { + return "allow generic function specialization"; + } + + bool diagnose(const Solution &solution, bool asNote = false) const override; + + bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override { + return diagnose(*commonFixes.front().first); + } + + static AllowGenericFunctionSpecialization * + create(ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator); + + static bool classof(const ConstraintFix *fix) { + return fix->getKind() == FixKind::AllowGenericFunctionSpecialization; + } +}; + class IgnoreOutOfPlaceThenStmt final : public ConstraintFix { IgnoreOutOfPlaceThenStmt(ConstraintSystem &cs, ConstraintLocator *locator) : ConstraintFix(cs, FixKind::IgnoreOutOfPlaceThenStmt, locator) {} diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index f0e415a02339b..446bc20739b25 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -1474,7 +1474,9 @@ static bool isGenericTypeDisambiguatingToken(Parser &P) { auto &tok = P.Tok; switch (tok.getKind()) { default: - return false; + // If this is the end of the expr (wouldn't match parseExprSequenceElement), + // prefer generic type list over an illegal unary postfix '>' operator. + return P.isStartOfSwiftDecl() || P.isStartOfStmt(/*prefer expr=*/true); case tok::r_paren: case tok::r_square: case tok::l_brace: diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 1ae4aec7d0798..e0a9dbadcf6e0 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -9338,7 +9338,12 @@ bool InvalidMemberReferenceWithinInitAccessor::diagnoseAsError() { } bool ConcreteTypeSpecialization::diagnoseAsError() { - emitDiagnostic(diag::not_a_generic_type, ConcreteType); + emitDiagnostic(diag::not_a_generic_type, resolveType(ConcreteType)); + return true; +} + +bool GenericFunctionSpecialization::diagnoseAsError() { + emitDiagnostic(diag::cannot_explicitly_specialize_generic_function); return true; } diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 0bb9e33fe5103..95bfef7de4a04 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -3116,7 +3116,18 @@ class ConcreteTypeSpecialization final : public FailureDiagnostic { ConcreteTypeSpecialization(const Solution &solution, Type concreteTy, ConstraintLocator *locator) : FailureDiagnostic(solution, locator), - ConcreteType(resolveType(concreteTy)) {} + ConcreteType(concreteTy) {} + + bool diagnoseAsError() override; +}; + +class GenericFunctionSpecialization final : public FailureDiagnostic { + ValueDecl *Decl; + +public: + GenericFunctionSpecialization(const Solution &solution, ValueDecl *decl, + ConstraintLocator *locator) + : FailureDiagnostic(solution, locator), Decl(decl) {} bool diagnoseAsError() override; }; diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index c447ea46e0268..d8b39ba976081 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -2604,6 +2604,18 @@ AllowConcreteTypeSpecialization::create(ConstraintSystem &cs, Type concreteTy, AllowConcreteTypeSpecialization(cs, concreteTy, locator); } +bool AllowGenericFunctionSpecialization::diagnose(const Solution &solution, + bool asNote) const { + GenericFunctionSpecialization failure(solution, Decl, getLocator()); + return failure.diagnose(asNote); +} + +AllowGenericFunctionSpecialization *AllowGenericFunctionSpecialization::create( + ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator) { + return new (cs.getAllocator()) + AllowGenericFunctionSpecialization(cs, decl, locator); +} + bool IgnoreOutOfPlaceThenStmt::diagnose(const Solution &solution, bool asNote) const { OutOfPlaceThenStmtFailure failure(solution, getLocator()); diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index d64723f07071a..305debe7bfbe0 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1903,9 +1903,9 @@ namespace { /// introduce them as an explicit generic arguments constraint. /// /// \returns true if resolving any of the specialization types failed. - bool addSpecializationConstraint( - ConstraintLocator *locator, Type boundType, - ArrayRef specializationArgs) { + void addSpecializationConstraint(ConstraintLocator *locator, Type boundType, + SourceLoc lAngleLoc, + ArrayRef specializationArgs) { // Resolve each type. SmallVector specializationArgTypes; auto options = @@ -1916,61 +1916,36 @@ namespace { options |= TypeResolutionFlags::AllowPackReferences; elementEnv = OuterExpansions.back(); } - const auto result = TypeResolution::resolveContextualType( + auto result = TypeResolution::resolveContextualType( specializationArg, CurDC, options, // Introduce type variables for unbound generics. OpenUnboundGenericType(CS, locator), HandlePlaceholderType(CS, locator), OpenPackElementType(CS, locator, elementEnv)); - if (result->hasError()) - return true; - + if (result->hasError()) { + auto &ctxt = CS.getASTContext(); + auto *repr = new (ctxt) PlaceholderTypeRepr(specializationArg->getLoc()); + result = PlaceholderType::get(ctxt, repr); + ctxt.Diags.diagnose(lAngleLoc, + diag::while_parsing_as_left_angle_bracket); + } specializationArgTypes.push_back(result); } - CS.addConstraint( - ConstraintKind::ExplicitGenericArguments, boundType, - PackType::get(CS.getASTContext(), specializationArgTypes), - locator); - return false; + auto constraint = Constraint::create( + CS, ConstraintKind::ExplicitGenericArguments, boundType, + PackType::get(CS.getASTContext(), specializationArgTypes), locator); + CS.addUnsolvedConstraint(constraint); + CS.activateConstraint(constraint); } Type visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *expr) { auto baseTy = CS.getType(expr->getSubExpr()); - - if (baseTy->isTypeVariableOrMember()) { - return baseTy; - } - - // We currently only support explicit specialization of generic types. - // FIXME: We could support explicit function specialization. - auto &de = CS.getASTContext().Diags; - if (baseTy->is()) { - de.diagnose(expr->getSubExpr()->getLoc(), - diag::cannot_explicitly_specialize_generic_function); - de.diagnose(expr->getLAngleLoc(), - diag::while_parsing_as_left_angle_bracket); - return Type(); - } - - if (AnyMetatypeType *meta = baseTy->getAs()) { - auto *overloadLocator = CS.getConstraintLocator(expr->getSubExpr()); - if (addSpecializationConstraint(overloadLocator, - meta->getInstanceType(), - expr->getUnresolvedParams())) { - return Type(); - } - - return baseTy; - } - - // FIXME: If the base type is a type variable, constrain it to a metatype - // of a bound generic type. - de.diagnose(expr->getSubExpr()->getLoc(), - diag::not_a_generic_definition); - de.diagnose(expr->getLAngleLoc(), - diag::while_parsing_as_left_angle_bracket); - return Type(); + auto *overloadLocator = CS.getConstraintLocator(expr->getSubExpr()); + addSpecializationConstraint( + overloadLocator, baseTy->getMetatypeInstanceType(), + expr->getLAngleLoc(), expr->getUnresolvedParams()); + return baseTy; } Type visitSequenceExpr(SequenceExpr *expr) { @@ -4082,10 +4057,9 @@ namespace { // Add explicit generic arguments, if there were any. if (expr->getGenericArgsRange().isValid()) { - if (addSpecializationConstraint( - CS.getConstraintLocator(expr), macroRefType, - expr->getGenericArgs())) - return Type(); + addSpecializationConstraint(CS.getConstraintLocator(expr), macroRefType, + expr->getGenericArgsRange().Start, + expr->getGenericArgs()); } // Form the applicable-function constraint. The result type diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index b1c3c103a3c65..4aba8bd7e5eca 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -13926,6 +13926,8 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint( // Bail out if we haven't selected an overload yet. auto simplifiedBoundType = simplifyType(type1, flags); + if (simplifiedBoundType->isPlaceholder()) + return SolutionKind::Solved; if (simplifiedBoundType->isTypeVariableOrMember()) return formUnsolved(); @@ -14018,13 +14020,12 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint( } } - if (!decl->getAsGenericContext()) - return SolutionKind::Error; - auto genericParams = getGenericParams(decl); - if (!genericParams) { - // FIXME: Record an error here that we're ignoring the parameters. - return SolutionKind::Solved; + if (!decl->getAsGenericContext() || !genericParams) { + return recordFix(AllowConcreteTypeSpecialization::create( + *this, type1, getConstraintLocator(locator))) + ? SolutionKind::Error + : SolutionKind::Solved; } // Map the generic parameters we have over to their opened types. @@ -14057,12 +14058,14 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint( } } - if (openedGenericParams.empty()) { + // FIXME: We could support explicit function specialization. + if (openedGenericParams.empty() || + (isa(decl) && !hasParameterPack)) { if (!shouldAttemptFixes()) return SolutionKind::Error; - return recordFix(AllowConcreteTypeSpecialization::create( - *this, type1, getConstraintLocator(locator))) + return recordFix(AllowGenericFunctionSpecialization::create( + *this, decl, getConstraintLocator(locator))) ? SolutionKind::Error : SolutionKind::Solved; } @@ -15193,6 +15196,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint( case FixKind::AllowAssociatedValueMismatch: case FixKind::GenericArgumentsMismatch: case FixKind::AllowConcreteTypeSpecialization: + case FixKind::AllowGenericFunctionSpecialization: case FixKind::IgnoreGenericSpecializationArityMismatch: case FixKind::IgnoreKeyPathSubscriptIndexMismatch: case FixKind::AllowMemberRefOnExistential: { diff --git a/test/Constraints/ambiguous_specialized_name_diagnostics.swift b/test/Constraints/ambiguous_specialized_name_diagnostics.swift index 322d004ed308c..90d363b8f1e88 100644 --- a/test/Constraints/ambiguous_specialized_name_diagnostics.swift +++ b/test/Constraints/ambiguous_specialized_name_diagnostics.swift @@ -42,7 +42,6 @@ func test() { S(t: 42).test() // expected-error {{ambiguous use of 'init(t:)'}} - // FIXME(diagnostics): This should produce ambiguity diagnostic too S.staticFn() - // expected-error@-1 {{generic parameter 'T' could not be inferred}} + // expected-error@-1 {{ambiguous use of 'staticFn()'}} } diff --git a/test/Parse/enum_element_pattern_swift4.swift b/test/Parse/enum_element_pattern_swift4.swift index 942f10420be94..4cdbea06d6f45 100644 --- a/test/Parse/enum_element_pattern_swift4.swift +++ b/test/Parse/enum_element_pattern_swift4.swift @@ -9,10 +9,13 @@ enum E { static func testE(e: E) { switch e { - case A(): // expected-error {{cannot specialize a non-generic definition}} + case A(): // expected-error {{cannot find type 'UndefinedTy' in scope}} // expected-note@-1 {{while parsing this '<' as a type parameter bracket}} + // expected-error@-2 {{cannot specialize non-generic type 'E'}} + // expected-error@-3 {{cannot call value of non-function type 'E'}} break - case B(): // expected-error {{cannot specialize a non-generic definition}} expected-note {{while parsing this '<' as a type parameter bracket}} + case B(): // expected-error {{cannot specialize non-generic type 'E'}} + // expected-error@-1 {{cannot call value of non-function type 'E'}} break default: break; @@ -22,10 +25,13 @@ enum E { func testE(e: E) { switch e { - case E.A(): // expected-error {{cannot specialize a non-generic definition}} + case E.A(): // expected-error {{cannot find type 'UndefinedTy' in scope}} // expected-note@-1 {{while parsing this '<' as a type parameter bracket}} + // expected-error@-2 {{cannot specialize non-generic type 'E'}} + // expected-error@-3 {{cannot call value of non-function type 'E'}} break - case E.B(): // expected-error {{cannot specialize a non-generic definition}} expected-note {{while parsing this '<' as a type parameter bracket}} + case E.B(): // expected-error {{cannot specialize non-generic type 'E'}} + // expected-error@-1 {{cannot call value of non-function type 'E'}} break case .C(): // expected-error {{pattern with associated values does not match enum case 'C'}} // expected-note@-1 {{remove associated values to make the pattern match}} {{10-12=}} diff --git a/test/Parse/generic_disambiguation.swift b/test/Parse/generic_disambiguation.swift index ebb900e3e8c47..e93d26f4a4efe 100644 --- a/test/Parse/generic_disambiguation.swift +++ b/test/Parse/generic_disambiguation.swift @@ -26,15 +26,21 @@ var a, b, c, d : Int _ = a < b _ = (a < b, c > d) // Parses as generic because of lparen after '>' -(a < b, c > (d)) // expected-error{{cannot specialize a non-generic definition}} -// expected-note@-1 {{while parsing this '<' as a type parameter bracket}} +(a < b, c > (d)) // expected-error{{cannot find type 'b' in scope}} +// expected-note@-1 2 {{while parsing this '<' as a type parameter bracket}} +// expected-error@-2 {{cannot specialize non-generic type 'Int'}} +// expected-error@-3 {{cannot call value of non-function type 'Int'}} +// expected-error@-4 {{cannot find type 'c' in scope}} // Parses as generic because of lparen after '>' -(a(d)) // expected-error{{cannot specialize a non-generic definition}} -// expected-note@-1 {{while parsing this '<' as a type parameter bracket}} +(a(d)) // expected-error{{cannot find type 'b' in scope}} +// expected-note@-1 2 {{while parsing this '<' as a type parameter bracket}} +// expected-error@-2 {{cannot specialize non-generic type 'Int'}} +// expected-error@-3 {{cannot call value of non-function type 'Int'}} +// expected-error@-4 {{cannot find type 'c' in scope}} _ = a>(b) _ = a > (b) -generic(0) // expected-error{{cannot explicitly specialize a generic function}} expected-note{{while parsing this '<' as a type parameter bracket}} +generic(0) // expected-error{{cannot explicitly specialize a generic function}} A.c() A>.c() diff --git a/test/Sema/generic-arg-list.swift b/test/Sema/generic-arg-list.swift new file mode 100644 index 0000000000000..04e7c1c24cf75 --- /dev/null +++ b/test/Sema/generic-arg-list.swift @@ -0,0 +1,41 @@ +// RUN: %target-typecheck-verify-swift + +extension Int { + func foo() -> Int {} + var bar: Int { + get {} + } + + func baz() -> Int {} + func baz(_ x: Int = 0) -> Int {} + + func gen() -> T {} // expected-note 2 {{in call to function 'gen()'}} +} + +// https://github.com/swiftlang/swift/issues/74857 +func test(i: Int) { + let _ = i.foo() // expected-error {{cannot specialize non-generic type '() -> Int'}} + + let _ = i.gen() // expected-error {{cannot explicitly specialize a generic function}} + // expected-error@-1 {{generic parameter 'T' could not be inferred}} + + let _ = 0.foo() // expected-error {{cannot specialize non-generic type '() -> Int'}} + + let _ = i.gen // expected-error {{cannot explicitly specialize a generic function}} + // expected-error@-1 {{generic parameter 'T' could not be inferred}} + let _ = i.bar // expected-error {{cannot specialize non-generic type 'Int'}} + let _ = 0.bar // expected-error {{cannot specialize non-generic type 'Int'}} +} + +extension Bool { + func foo() -> T {} +} + +let _: () -> Bool = false.foo // expected-error {{cannot explicitly specialize a generic function}} + +func foo(_ x: Int) { + _ = { + _ = x // expected-error {{cannot specialize non-generic type 'Int'}} + } +} +