diff --git a/changelog/dmd.basic-vs-primary-type.dd b/changelog/dmd.basic-vs-primary-type.dd new file mode 100644 index 000000000000..91e792020171 --- /dev/null +++ b/changelog/dmd.basic-vs-primary-type.dd @@ -0,0 +1,13 @@ +The term *basic type* is now *primary type* + +The parser now uses the term *primary type* for what used to be referred to as *basic type.* +The term *basic type* is used specifically for type expressions that are not immediately recursive. + +A *basic type* is a *fundamental type* (those which have keywords) +or a type given by an identifier, a `typeof`, a `mixin`, or a `__traits`. +Absent from this list are `__vector` types and types spelled out using a qualifier and parentheses (e.g. `const(int)`). + +A *primary type* is a *basic type* or a `__vector` type or a qualified type. + +For the most part, *primary type* is the term you want to use and will see in error messages now. +There are some corners where indeed a *basic type* is required. diff --git a/changelog/dmd.const-base.dd b/changelog/dmd.const-base.dd new file mode 100644 index 000000000000..adcfe3f527a2 --- /dev/null +++ b/changelog/dmd.const-base.dd @@ -0,0 +1,18 @@ +Specifying a qualified type as a base class or interface is an error now + +A type like `const(Object)` could be used as a base class in the base class list +of a class or interface declaration or of an anonymous class object. +There, qualifiers were simply ignored semantically. + +Explicitly qualifying types in base class lists is a parse error now. + +This only affects parsing. +If a `mixin` or `typeof` or an identifier is used, nothing changes. +If it resolves to a qualified type, +the qualifier is ignored. +--- +class C : const(Object) { } // Parse error now +auto obj = new class const(Object) { }; // Parse error now +--- +There is no deprecation period. +The fix is to remove the unnecessary and misleading qualifier from your code. diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 33e0e5a11310..535095562d8a 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -2813,7 +2813,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { case TOK.rightParenthesis: if (storageClass != 0 || udas !is null) - error("basic type expected, not `)`"); + error("primary type expected, not `)`"); break; case TOK.dotDotDot: @@ -3028,7 +3028,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); int alt = 0; const typeLoc = token.loc; - memtype = parseBasicType(); + memtype = parsePrimaryType(); memtype = parseDeclarator(memtype, alt, null); checkCstyleTypeSyntax(typeLoc, memtype, alt, null); } @@ -3140,7 +3140,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else { Token* t = &token; - if (isBasicType(&t)) + if (isPrimaryType(&t)) { error("named enum cannot declare member with type", (*t).toChars()); nextToken(); @@ -3541,7 +3541,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer const typeLoc = token.loc; AST.Type t; - t = parseBasicType(); + t = parsePrimaryType(); if (pdeclLoc) *pdeclLoc = token.loc; @@ -3553,7 +3553,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return t; } - private AST.Type parseBasicType(bool dontLookDotIdents = false) + private AST.Type parseBasicType(bool dontLookDotIdents = false, bool parsingPrimaryType = false) { AST.Type t; Loc loc; @@ -3682,11 +3682,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { // ident!(template_arguments) auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments()); - t = parseBasicTypeStartingAt(new AST.TypeInstance(loc, tempinst), dontLookDotIdents); + t = parsePrimaryTypeStartingAt(new AST.TypeInstance(loc, tempinst), dontLookDotIdents); } else { - t = parseBasicTypeStartingAt(new AST.TypeIdentifier(loc, id), dontLookDotIdents); + t = parsePrimaryTypeStartingAt(new AST.TypeIdentifier(loc, id), dontLookDotIdents); } break; @@ -3702,14 +3702,31 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.dot: // Leading . as in .foo - t = parseBasicTypeStartingAt(new AST.TypeIdentifier(token.loc, Id.empty), dontLookDotIdents); + t = parsePrimaryTypeStartingAt(new AST.TypeIdentifier(token.loc, Id.empty), dontLookDotIdents); break; case TOK.typeof_: // typeof(expression) - t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents); + t = parsePrimaryTypeStartingAt(parseTypeof(), dontLookDotIdents); break; + default: + immutable char* kind = parsingPrimaryType ? "primary" : "basic"; + error("%s type expected, not `%s`", kind, token.toChars()); + if (token.value == TOK.else_) + eSink.errorSupplemental(token.loc, "There's no `static else`, use `else` instead."); + t = AST.Type.terror; + break; + } + return t; + } + + private AST.Type parsePrimaryType(bool dontLookDotIdents = false) + { + AST.Type t; + //printf("parsePrimaryType()\n"); + switch (token.value) + { case TOK.vector: t = parseVector(); break; @@ -3757,20 +3774,17 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer break; default: - error("basic type expected, not `%s`", token.toChars()); - if (token.value == TOK.else_) - eSink.errorSupplemental(token.loc, "There's no `static else`, use `else` instead."); - t = AST.Type.terror; + t = parseBasicType(dontLookDotIdents, /+parsingPrimaryType:+/true); break; } return t; } - private AST.Type parseBasicTypeStartingAt(AST.TypeQualified tid, bool dontLookDotIdents) + private AST.Type parsePrimaryTypeStartingAt(AST.TypeQualified tid, bool dontLookDotIdents) { AST.Type maybeArray = null; // See https://issues.dlang.org/show_bug.cgi?id=1215 - // A basic type can look like MyType (typical case), but also: + // A primary type can look like MyType (typical case), but also: // MyType.T -> A type // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple) // MyType[expr].T -> A type. @@ -4491,7 +4505,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else { - ts = parseBasicType(); + ts = parsePrimaryType(); ts = parseTypeSuffixes(ts); } } @@ -4947,7 +4961,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (udas) error("user-defined attributes not allowed for `alias` declarations"); - auto t = parseBasicType(); + auto t = parsePrimaryType(); t = parseTypeSuffixes(t); if (token.value == TOK.identifier) { @@ -5092,7 +5106,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { // function type (parameters) { statements... } // delegate type (parameters) { statements... } - tret = parseBasicType(); + tret = parsePrimaryType(); tret = parseTypeSuffixes(tret); // function return type } @@ -7201,7 +7215,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer break; } - if (!isBasicType(&t)) + if (!isPrimaryType(&t)) { goto Lisnot; } @@ -7230,10 +7244,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return false; } - // pt = test token. If found, pt is set to the token after BasicType - private bool isBasicType(Token** pt) + // pt = test token. If found, pt is set to the token after PrimaryType + private bool isPrimaryType(Token** pt) { - // This code parallels parseBasicType() + // This code parallels parsePrimaryType() Token* t = *pt; switch (t.value) { @@ -7736,7 +7750,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer default: { - if (!isBasicType(&t)) + if (!isPrimaryType(&t)) return false; L2: int tmp = false; @@ -8775,7 +8789,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { StorageClass stc = parseTypeCtor(); - AST.Type t = parseBasicType(); + AST.Type t = parsePrimaryType(); t = t.addSTC(stc); if (stc == 0 && token.value == TOK.dot) @@ -9543,7 +9557,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } const stc = parseTypeCtor(); - auto t = parseBasicType(true); + auto t = parsePrimaryType(true); t = parseTypeSuffixes(t); t = t.addSTC(stc); if (t.ty == Taarray) diff --git a/compiler/test/compilable/test1353.d b/compiler/test/compilable/test1353.d index b724aa818b1e..cb0f6487fb8e 100644 --- a/compiler/test/compilable/test1353.d +++ b/compiler/test/compilable/test1353.d @@ -6,9 +6,9 @@ interface D(X) {} void fun() { - class T : typeof(new A), .B, const(C), D!int {} + class T : typeof(new A), .B, C, D!int {} version(none) { - class U : int, float, __vector(int[3]) {} + class U : int, float {} } } diff --git a/compiler/test/fail_compilation/b20780.d b/compiler/test/fail_compilation/b20780.d index ec6917bb58ae..23a657012591 100644 --- a/compiler/test/fail_compilation/b20780.d +++ b/compiler/test/fail_compilation/b20780.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/b20780.d(10): Error: `@identifier` or `@(ArgumentList)` expected, not `@)` fail_compilation/b20780.d(11): Error: `@identifier` or `@(ArgumentList)` expected, not `@,` -fail_compilation/b20780.d(11): Error: basic type expected, not `,` +fail_compilation/b20780.d(11): Error: primary type expected, not `,` --- */ diff --git a/compiler/test/fail_compilation/diag19225.d b/compiler/test/fail_compilation/diag19225.d index a43a7e10e07a..4b34becb5e4d 100644 --- a/compiler/test/fail_compilation/diag19225.d +++ b/compiler/test/fail_compilation/diag19225.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag19225.d(14): Error: basic type expected, not `else` +fail_compilation/diag19225.d(14): Error: primary type expected, not `else` fail_compilation/diag19225.d(14): There's no `static else`, use `else` instead. fail_compilation/diag19225.d(14): Error: found `else` without a corresponding `if`, `version` or `debug` statement fail_compilation/diag19225.d(15): Error: unmatched closing brace diff --git a/compiler/test/fail_compilation/e15876_3.d b/compiler/test/fail_compilation/e15876_3.d index 7e9d70913d25..9358004bb840 100644 --- a/compiler/test/fail_compilation/e15876_3.d +++ b/compiler/test/fail_compilation/e15876_3.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/e15876_3.d(28): Error: unexpected `(` in declarator -fail_compilation/e15876_3.d(28): Error: basic type expected, not `=` +fail_compilation/e15876_3.d(28): Error: primary type expected, not `=` fail_compilation/e15876_3.d(29): Error: found `End of File` when expecting `(` fail_compilation/e15876_3.d(29): Error: found `End of File` instead of statement fail_compilation/e15876_3.d(29): Error: expression expected, not `End of File` diff --git a/compiler/test/fail_compilation/e15876_5.d b/compiler/test/fail_compilation/e15876_5.d index 42183b26bd09..a3b573719c22 100644 --- a/compiler/test/fail_compilation/e15876_5.d +++ b/compiler/test/fail_compilation/e15876_5.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/e15876_5.d(17): Error: basic type expected, not `End of File` +fail_compilation/e15876_5.d(17): Error: primary type expected, not `End of File` fail_compilation/e15876_5.d(17): Error: semicolon expected to close `alias` declaration, not `End of File` fail_compilation/e15876_5.d(17): Error: matching `}` expected following compound statement, not `End of File` fail_compilation/e15876_5.d(16): unmatched `{` diff --git a/compiler/test/fail_compilation/enum_member.d b/compiler/test/fail_compilation/enum_member.d index 94c6f9811952..5023d6d845b1 100644 --- a/compiler/test/fail_compilation/enum_member.d +++ b/compiler/test/fail_compilation/enum_member.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/enum_member.d(14): Error: basic type expected, not `for` +fail_compilation/enum_member.d(14): Error: primary type expected, not `for` fail_compilation/enum_member.d(15): Error: no identifier for declarator `T` fail_compilation/enum_member.d(15): Error: found `@` when expecting `,` fail_compilation/enum_member.d(22): Error: found `}` when expecting `identifier` diff --git a/compiler/test/fail_compilation/fail15667.d b/compiler/test/fail_compilation/fail15667.d index ce4940ffa31b..78ed75fbef43 100644 --- a/compiler/test/fail_compilation/fail15667.d +++ b/compiler/test/fail_compilation/fail15667.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/imports/a15667.d(16): Error: basic type expected, not `;` +fail_compilation/imports/a15667.d(16): Error: primary type expected, not `;` fail_compilation/imports/a15667.d(19): Error: declaration expected following attribute, not end of file --- */ diff --git a/compiler/test/fail_compilation/ice11982.d b/compiler/test/fail_compilation/ice11982.d index f500700f674b..efa69f7f0cfe 100644 --- a/compiler/test/fail_compilation/ice11982.d +++ b/compiler/test/fail_compilation/ice11982.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/ice11982.d(22): Error: basic type expected, not `scope` +fail_compilation/ice11982.d(22): Error: primary type expected, not `scope` fail_compilation/ice11982.d(22): Error: found `scope` when expecting `;` following expression fail_compilation/ice11982.d(22): expression: `new _error_` -fail_compilation/ice11982.d(22): Error: basic type expected, not `}` +fail_compilation/ice11982.d(22): Error: primary type expected, not `}` fail_compilation/ice11982.d(22): Error: missing `{ ... }` for function literal fail_compilation/ice11982.d(22): Error: C style cast illegal, use `cast(funk)function _error_() { diff --git a/compiler/test/fail_compilation/ice15127.d b/compiler/test/fail_compilation/ice15127.d index afc6419725ff..98dbcd99089d 100644 --- a/compiler/test/fail_compilation/ice15127.d +++ b/compiler/test/fail_compilation/ice15127.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice15127.d(17): Error: basic type expected, not `struct` +fail_compilation/ice15127.d(17): Error: primary type expected, not `struct` fail_compilation/ice15127.d(17): Error: identifier expected for template value parameter fail_compilation/ice15127.d(17): Error: found `struct` when expecting `)` fail_compilation/ice15127.d(17): Error: found `ExampleStruct` when expecting `=` diff --git a/compiler/test/fail_compilation/misc_parser_err_cov1.d b/compiler/test/fail_compilation/misc_parser_err_cov1.d index 4a8875d6d69c..fcd25b2d5b4c 100644 --- a/compiler/test/fail_compilation/misc_parser_err_cov1.d +++ b/compiler/test/fail_compilation/misc_parser_err_cov1.d @@ -2,8 +2,8 @@ REQUIRED_ARGS: -verrors=0 TEST_OUTPUT: --- -fail_compilation/misc_parser_err_cov1.d(29): Error: basic type expected, not `)` -fail_compilation/misc_parser_err_cov1.d(30): Error: basic type expected, not `)` +fail_compilation/misc_parser_err_cov1.d(29): Error: primary type expected, not `)` +fail_compilation/misc_parser_err_cov1.d(30): Error: primary type expected, not `)` fail_compilation/misc_parser_err_cov1.d(31): Error: `__traits(identifier, args...)` expected fail_compilation/misc_parser_err_cov1.d(31): Error: semicolon expected following auto declaration, not `o` fail_compilation/misc_parser_err_cov1.d(31): Error: expression expected, not `)` diff --git a/compiler/test/fail_compilation/qualbaseclass1.d b/compiler/test/fail_compilation/qualbaseclass1.d new file mode 100644 index 000000000000..675150d2cd2e --- /dev/null +++ b/compiler/test/fail_compilation/qualbaseclass1.d @@ -0,0 +1,12 @@ +/* TEST_OUTPUT: +--- +fail_compilation\qualbaseclass1.d(101): Error: basic type expected, not `const` +fail_compilation\qualbaseclass1.d(101): Error: { } expected following `class` declaration +fail_compilation\qualbaseclass1.d(101): Error: variable name expected after type `const(Object)`, not `{` +fail_compilation\qualbaseclass1.d(101): Error: declaration expected, not `{` +--- + */ + +#line 100 + +class C : const(Object) { } diff --git a/compiler/test/fail_compilation/qualbaseclass2.d b/compiler/test/fail_compilation/qualbaseclass2.d new file mode 100644 index 000000000000..e9f0fc51439d --- /dev/null +++ b/compiler/test/fail_compilation/qualbaseclass2.d @@ -0,0 +1,15 @@ +/* TEST_OUTPUT: +--- +fail_compilation\qualbaseclass2.d(103): Error: basic type expected, not `const` +fail_compilation\qualbaseclass2.d(103): Error: `{ members }` expected for anonymous class +fail_compilation\qualbaseclass2.d(103): Error: semicolon expected following auto declaration, not `const` +fail_compilation/qualbaseclass2.d(103): Error: variable name expected after type `const(Object)`, not `{` +--- + */ + +#line 100 + +void test() +{ + auto obj = new class () const(Object) { }; +} diff --git a/compiler/test/fail_compilation/udaparams.d b/compiler/test/fail_compilation/udaparams.d index 06f4bd8b67b3..33231943a013 100644 --- a/compiler/test/fail_compilation/udaparams.d +++ b/compiler/test/fail_compilation/udaparams.d @@ -18,10 +18,10 @@ fail_compilation/udaparams.d(53): Error: semicolon expected to close `alias` dec fail_compilation/udaparams.d(53): Error: declaration expected, not `1` fail_compilation/udaparams.d(54): Error: semicolon expected to close `alias` declaration, not `=>` fail_compilation/udaparams.d(54): Error: declaration expected, not `1` -fail_compilation/udaparams.d(57): Error: basic type expected, not `@` +fail_compilation/udaparams.d(57): Error: primary type expected, not `@` fail_compilation/udaparams.d(57): Error: identifier expected for template value parameter fail_compilation/udaparams.d(57): Error: found `@` when expecting `)` -fail_compilation/udaparams.d(57): Error: basic type expected, not `3` +fail_compilation/udaparams.d(57): Error: primary type expected, not `3` fail_compilation/udaparams.d(57): Error: found `3` when expecting `)` fail_compilation/udaparams.d(57): Error: semicolon expected following function declaration, not `)` fail_compilation/udaparams.d(57): Error: variable name expected after type `T`, not `)`