diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index ed1caac8d83da..c6cfc54e2e4ee 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8002,12 +8002,6 @@ NOTE(unsafe_decl_here,none, // MARK: Value Generics //===----------------------------------------------------------------------===// -ERROR(invalid_value_value_generic,none, - "%0 requires that %1 must be a valid value for %2", - (Type, Type, Type)) -NOTE(invalid_value_value_generic_requirement,none, - "requirement specified as %0 == %1%2", - (Type, Type, StringRef)) ERROR(cannot_pass_type_for_value_generic,none, "cannot pass type %0 as a value for generic value %1", (Type, Type)) ERROR(value_type_used_in_type_parameter,none, @@ -8029,6 +8023,8 @@ ERROR(value_generics_missing_feature,none, ERROR(availability_value_generic_type_only_version_newer, none, "values in generic types are only available in %0 %1 or newer", (StringRef, llvm::VersionTuple)) +ERROR(invalid_value_for_type_same_type,none, + "cannot constrain type parameter %0 to be integer %1", (Type, Type)) #define UNDEFINE_DIAGNOSTIC_MACROS #include "DefineDiagnosticMacros.h" diff --git a/lib/AST/RequirementMachine/Diagnostics.cpp b/lib/AST/RequirementMachine/Diagnostics.cpp index 82c6e31898555..47f47e21ff137 100644 --- a/lib/AST/RequirementMachine/Diagnostics.cpp +++ b/lib/AST/RequirementMachine/Diagnostics.cpp @@ -261,6 +261,18 @@ bool swift::rewriting::diagnoseRequirementErrors( diagnosedError = true; break; } + + case RequirementError::Kind::InvalidValueForTypeSameType: { + auto req = error.getRequirement(); + + if (req.hasError()) + break; + + ctx.Diags.diagnose(loc, diag::invalid_value_for_type_same_type, + req.getFirstType(), req.getSecondType()); + diagnosedError = true; + break; + } } } diff --git a/lib/AST/RequirementMachine/Diagnostics.h b/lib/AST/RequirementMachine/Diagnostics.h index a722aef9f49cd..e336842684d4b 100644 --- a/lib/AST/RequirementMachine/Diagnostics.h +++ b/lib/AST/RequirementMachine/Diagnostics.h @@ -62,6 +62,9 @@ struct RequirementError { /// A value generic type was used to same-type to an unrelated type, /// e.g. 'where N == Int' where N == 'let N: Int'. InvalidValueGenericSameType, + /// A value type, either an integer '123' or a value generic parameter 'N', + /// was used to same type a regular type parameter, e.g. 'T == 123'. + InvalidValueForTypeSameType, } kind; private: @@ -177,6 +180,13 @@ struct RequirementError { Requirement requirement(RequirementKind::Conformance, subjectType, constraint); return {Kind::InvalidValueGenericSameType, requirement, loc}; } + + static RequirementError forInvalidValueForTypeSameType(Type subjectType, + Type constraint, + SourceLoc loc) { + Requirement requirement(RequirementKind::Conformance, subjectType, constraint); + return {Kind::InvalidValueForTypeSameType, requirement, loc}; + } }; /// Policy for the fixit that transforms 'T : S' where 'S' is not a protocol diff --git a/lib/AST/RequirementMachine/RequirementLowering.cpp b/lib/AST/RequirementMachine/RequirementLowering.cpp index a7476e6dd8219..9739f202e6c0a 100644 --- a/lib/AST/RequirementMachine/RequirementLowering.cpp +++ b/lib/AST/RequirementMachine/RequirementLowering.cpp @@ -250,6 +250,18 @@ static void desugarSameTypeRequirement( } } + if (!firstType->isValueParameter() && secondType->is()) { + errors.push_back(RequirementError::forInvalidValueForTypeSameType( + sugaredFirstType, secondType, loc)); + return true; + } + + if (!secondType->isValueParameter() && firstType->is()) { + errors.push_back(RequirementError::forInvalidValueForTypeSameType( + secondType, sugaredFirstType, loc)); + return true; + } + if (firstType->isTypeParameter() && secondType->isTypeParameter()) { result.emplace_back(kind, sugaredFirstType, secondType); return true; diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 29ef757772952..5ab6e916b3242 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -176,9 +176,9 @@ ParserResult Parser::parseTypeSimple( tildeLoc = consumeToken(); } - // Eat any '-' preceding the type. + // Eat any '-' preceding integer literals. SourceLoc minusLoc; - if (Tok.isMinus()) { + if (Tok.isMinus() && peekToken().is(tok::integer_literal)) { minusLoc = consumeToken(); } @@ -1588,13 +1588,26 @@ bool Parser::canParseType() { return false; break; case tok::oper_prefix: - if (Tok.getText() != "~" && Tok.getText() != "-") { + if (!Tok.isTilde() && !Tok.isMinus()) { return false; } - consumeToken(); - if (!canParseTypeIdentifier()) - return false; + // '~' can only appear before type identifiers like '~Copyable'. + if (Tok.isTilde()) { + consumeToken(); + + if (!canParseTypeIdentifier()) + return false; + } + + // '-' can only appear before integers being used as types like '-123'. + if (Tok.isMinus()) { + consumeToken(); + + if (!Tok.is(tok::integer_literal)) + return false; + } + break; case tok::kw_protocol: return canParseOldStyleProtocolComposition(); diff --git a/test/Parse/integer_types.swift b/test/Parse/integer_types.swift new file mode 100644 index 0000000000000..3ac09e87669ff --- /dev/null +++ b/test/Parse/integer_types.swift @@ -0,0 +1,32 @@ +// RUN: %target-typecheck-verify-swift + +let a: 123 // expected-error {{integer unexpectedly used in a type position}} + +let b: -123 // expected-error {{integer unexpectedly used in a type position}} + +let c: -Int // expected-error {{expected type}} + // expected-error@-1 {{consecutive statements on a line must be separated by ';'}} + // expected-error@-2 {{unary operator '-' cannot be applied to an operand of type 'Int.Type'}} + +struct Generic {} // expected-note {{'T' declared as parameter to type 'Generic'}} + // expected-note@-1 {{'T' declared as parameter to type 'Generic'}} + +extension Generic where T == 123 {} // expected-error {{cannot constrain type parameter 'T' to be integer '123'}} + +extension Generic where T == -123 {} // expected-error {{cannot constrain type parameter 'T' to be integer '-123'}} + +extension Generic where T == -Int {} // expected-error {{expected type}} + // expected-error@-1 {{expected '{' in extension}} + +let d = Generic<123>.self // expected-error {{integer unexpectedly used in a type position}} + +// FIXME: This should at least be parsable...? +let e = Generic<-123>.self // expected-error {{generic parameter 'T' could not be inferred}} + // expected-error@-1 {{missing whitespace between '<' and '-' operators}} + // expected-error@-2 {{'>' is not a postfix unary operator}} + // expected-note@-3 {{explicitly specify the generic arguments to fix this issue}} + +let f = Generic<-Int>.self // expected-error {{generic parameter 'T' could not be inferred}} + // expected-error@-1 {{missing whitespace between '<' and '-' operators}} + // expected-error@-2 {{'>' is not a postfix unary operator}} + // expected-note@-3 {{explicitly specify the generic arguments to fix this issue}} diff --git a/test/Sema/value_generics.swift b/test/Sema/value_generics.swift index f385647914ee9..231b86d81f6e4 100644 --- a/test/Sema/value_generics.swift +++ b/test/Sema/value_generics.swift @@ -48,6 +48,9 @@ func e(with a: A) {} // expected-error {{cannot pass type 'Int' as a value struct Generic {} struct GenericWithIntParam {} +extension Generic where T == 123 {} // expected-error {{cannot constrain type parameter 'T' to be integer '123'}} +extension Generic where T == 123.Type {} // expected-error {{integer unexpectedly used in a type position}} + func f(_: Generic<123>) {} // expected-error {{integer unexpectedly used in a type position}} func g(_: Generic) {} // expected-error {{cannot use value type 'N' for generic argument 'T'}} func h(_: (Int, 123)) {} // expected-error {{integer unexpectedly used in a type position}}