Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions compiler/src/dmd/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -2188,16 +2188,19 @@ extern (C++) final class DotIdExp : UnaExp
bool noderef; // true if the result of the expression will never be dereferenced
bool wantsym; // do not replace Symbol with its initializer during semantic()
bool arrow; // ImportC: if -> instead of .
/// Location of the identifier (for accurate error reporting). Loc.initial when not from source.
Loc identLoc;

extern (D) this(Loc loc, Expression e, Identifier ident) @safe
extern (D) this(Loc loc, Expression e, Identifier ident, Loc identLoc = Loc.initial) @safe
{
super(loc, EXP.dotIdentifier, e);
this.ident = ident;
this.identLoc = identLoc;
}

static DotIdExp create(Loc loc, Expression e, Identifier ident) @safe
static DotIdExp create(Loc loc, Expression e, Identifier ident, Loc identLoc = Loc.initial) @safe
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need update this in the header too

{
return new DotIdExp(loc, e, ident);
return new DotIdExp(loc, e, ident, identLoc);
}

override void accept(Visitor v)
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@ class DotIdExp final : public UnaExp
d_bool noderef; // true if the result of the expression will never be dereferenced
d_bool wantsym; // do not replace Symbol with its initializer during semantic()
d_bool arrow; // ImportC: if -> instead of .
Loc identLoc; // location of the identifier (for accurate error reporting)

static DotIdExp *create(Loc loc, Expression *e, Identifier *ident);
void accept(Visitor *v) override { v->visit(this); }
Expand Down
12 changes: 8 additions & 4 deletions compiler/src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -2187,7 +2187,11 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
}

if (!s)
return ue.e1.type.getProperty(sc, loc, ident, 0, ue.e1);
{
auto die = ue.isDotIdExp();
const identLoc = (die && die.identLoc != Loc.initial) ? die.identLoc : Loc.initial;
return ue.e1.type.getProperty(sc, loc, ident, 0, ue.e1, identLoc);
}

FuncDeclaration f = s.isFuncDeclaration();
if (f)
Expand Down Expand Up @@ -15700,7 +15704,7 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length)
{
// bypass checkPurity
return exp.e1.type.dotExp(sc, exp.e1, exp.ident, cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref));
return exp.e1.type.dotExp(sc, exp.e1, exp.ident, cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref), exp.identLoc);
}

if (!exp.e1.isDotExp())
Expand Down Expand Up @@ -16065,7 +16069,7 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
Expression e = new PtrExp(exp.loc, exp.e1);
e = e.expressionSemantic(sc);
const newFlag = cast(DotExpFlag) (gag * DotExpFlag.gag | exp.noderef * DotExpFlag.noDeref);
return e.type.dotExp(sc, e, exp.ident, newFlag);
return e.type.dotExp(sc, e, exp.ident, newFlag, exp.identLoc);
}
else if (exp.ident == Id.__xalignof &&
exp.e1.isVarExp() &&
Expand All @@ -16092,7 +16096,7 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)

const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag);

Expression e = dotExp(exp.e1.type, sc, exp.e1, exp.ident, flag);
Expression e = dotExp(exp.e1.type, sc, exp.e1, exp.ident, flag, exp.identLoc);
if (e)
{
e = e.expressionSemantic(sc);
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -2794,6 +2794,7 @@ class DotIdExp final : public UnaExp
bool noderef;
bool wantsym;
bool arrow;
Loc identLoc; // location of the identifier (for accurate error reporting)
static DotIdExp* create(Loc loc, Expression* e, Identifier* ident);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and in frontend.h here too

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! updated the C++ headers as well added identLoc parameter (with default Loc()) to DotIdExp::create in both compiler/src/dmd/expression.h and compiler/src/dmd/frontend.h.

void accept(Visitor* v) override;
};
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dmd/parse.d
Original file line number Diff line number Diff line change
Expand Up @@ -9064,6 +9064,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value == TOK.identifier)
{
Identifier id = token.ident;
const identLoc = token.loc;

nextToken();
if (token.value == TOK.not && peekNext() != TOK.is_ && peekNext() != TOK.in_)
Expand All @@ -9072,7 +9073,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
e = new AST.DotTemplateInstanceExp(loc, e, id, tiargs);
}
else
e = new AST.DotIdExp(loc, e, id);
e = new AST.DotIdExp(loc, e, id, identLoc);
continue;
}
if (token.value == TOK.new_)
Expand Down
51 changes: 27 additions & 24 deletions compiler/src/dmd/typesem.d
Original file line number Diff line number Diff line change
Expand Up @@ -5014,11 +5014,12 @@ Expression defaultInitLiteral(Type t, Loc loc)
* ident = the identifier of the property
* flag = if flag & 1, don't report "not a property" error and just return NULL.
* src = expression for type `t` or null.
* identLoc = location of the identifier (for accurate error reporting); use when != Loc.initial.
* Returns:
* expression representing the property, or null if not a property and (flag & 1)
*/
Expression getProperty(Type t, Scope* scope_, Loc loc, Identifier ident, int flag,
Expression src = null)
Expression src = null, Loc identLoc = Loc.initial)
{
Expression visitType(Type mt)
{
Expand Down Expand Up @@ -5094,21 +5095,22 @@ Expression getProperty(Type t, Scope* scope_, Loc loc, Identifier ident, int fla
if (mt == Type.terror)
return ErrorExp.get();

const errLoc = identLoc != Loc.initial ? identLoc : loc;
if (s)
{
error(loc, "no property `%s` for type `%s`", ident.toErrMsg(), mt.toErrMsg());
error(errLoc, "no property `%s` for type `%s`", ident.toErrMsg(), mt.toErrMsg());
errorSupplemental(s.loc, "did you mean `%s`?", ident == s.ident ? s.toPrettyChars() : s.toErrMsg());
}
else if (ident == Id.opCall && mt.ty == Tclass)
error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toErrMsg(), mt.toErrMsg(), mt.toPrettyChars());
error(errLoc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toErrMsg(), mt.toErrMsg(), mt.toPrettyChars());

else if (const n = importHint(ident.toString()))
error(loc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toErrMsg(), mt.toErrMsg(), cast(int)n.length, n.ptr);
error(errLoc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toErrMsg(), mt.toErrMsg(), cast(int)n.length, n.ptr);
else
{
if (src)
{
error(loc, "no property `%s` for `%s` of type `%s`",
error(errLoc, "no property `%s` for `%s` of type `%s`",
ident.toErrMsg(), src.toErrMsg(), mt.toPrettyChars(true));
auto s2 = scope_.search_correct(ident);
// UFCS
Expand All @@ -5125,7 +5127,7 @@ Expression getProperty(Type t, Scope* scope_, Loc loc, Identifier ident, int fla
}
}
else
error(loc, "no property `%s` for type `%s`", ident.toErrMsg(), mt.toPrettyChars(true));
error(errLoc, "no property `%s` for type `%s`", ident.toErrMsg(), mt.toPrettyChars(true));

if (auto dsym = derefType.toDsymbol(scope_))
{
Expand Down Expand Up @@ -5425,7 +5427,7 @@ Expression getProperty(Type t, Scope* scope_, Loc loc, Identifier ident, int fla
}
else
{
e = mt.toBasetype().getProperty(scope_, loc, ident, flag);
e = mt.toBasetype().getProperty(scope_, loc, ident, flag, null, identLoc);
}
return e;
}
Expand Down Expand Up @@ -6151,7 +6153,7 @@ void resolve(Type mt, Loc loc, Scope* sc, out Expression pe, out Type pt, out Ds
* Returns:
* resulting expression with e.ident resolved
*/
Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag flag)
Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag flag, Loc identLoc = Loc.initial)
{
enum LOGDOTEXP = false;
if (LOGDOTEXP)
Expand Down Expand Up @@ -6228,7 +6230,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
e = new StringExp(e.loc, e.toString());
}
else
e = mt.getProperty(sc, e.loc, ident, flag & DotExpFlag.gag);
e = mt.getProperty(sc, e.loc, ident, flag & DotExpFlag.gag, null, identLoc);

Lreturn:
if (e)
Expand Down Expand Up @@ -6288,7 +6290,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
break;

default:
e = mt.Type.getProperty(sc, e.loc, ident, flag);
e = mt.Type.getProperty(sc, e.loc, ident, flag, null, identLoc);
break;
}
}
Expand Down Expand Up @@ -6339,7 +6341,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
break;

default:
e = mt.Type.getProperty(sc, e.loc, ident, flag);
e = mt.Type.getProperty(sc, e.loc, ident, flag, null, identLoc);
break;
}
}
Expand Down Expand Up @@ -6389,11 +6391,11 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
ident == Id.nan || ident == Id.infinity || ident == Id.epsilon)
{
auto vet = mt.basetype.isTypeSArray().next; // vector element type
if (auto ev = getProperty(vet, sc, e.loc, ident, DotExpFlag.gag))
if (auto ev = getProperty(vet, sc, e.loc, ident, DotExpFlag.gag, null, identLoc))
return ev.castTo(sc, mt); // 'broadcast' ev to the vector elements
}

return mt.basetype.dotExp(sc, e.castTo(sc, mt.basetype), ident, flag);
return mt.basetype.dotExp(sc, e.castTo(sc, mt.basetype), ident, flag, identLoc);
}

Expression visitArray(TypeArray mt)
Expand Down Expand Up @@ -6541,7 +6543,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
}
// References just forward things along
return mt.next.dotExp(sc, e, ident, flag);
return mt.next.dotExp(sc, e, ident, flag, identLoc);
}

Expression visitDelegate(TypeDelegate mt)
Expand Down Expand Up @@ -6716,7 +6718,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
// https://issues.dlang.org/show_bug.cgi?id=14010
if (!sc.inCfile && ident == Id._mangleof)
{
return mt.getProperty(sc, e.loc, ident, flag & 1);
return mt.getProperty(sc, e.loc, ident, flag & 1, null, identLoc);
}

/* If e.tupleof
Expand Down Expand Up @@ -6976,7 +6978,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
// https://issues.dlang.org/show_bug.cgi?id=14010
if (ident == Id._mangleof)
{
return mt.getProperty(sc, e.loc, ident, flag & 1);
return mt.getProperty(sc, e.loc, ident, flag & 1, null, identLoc);
}

if (mt.sym.semanticRun < PASS.semanticdone)
Expand All @@ -6987,24 +6989,25 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
{
if (ident == Id._init)
{
return mt.getProperty(sc, e.loc, ident, flag & 1);
return mt.getProperty(sc, e.loc, ident, flag & 1, null, identLoc);
}

/* Allow special enums to not need a member list
*/
if ((ident == Id.max || ident == Id.min) && (mt.sym.members || !mt.sym.isSpecial()))
{
return mt.getProperty(sc, e.loc, ident, flag & 1);
return mt.getProperty(sc, e.loc, ident, flag & 1, null, identLoc);
}

Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, DotExpFlag.gag);
Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, DotExpFlag.gag, identLoc);
if (!(flag & 1) && !res)
{
const errLoc = identLoc != Loc.initial ? identLoc : e.loc;
if (auto ns = mt.sym.search_correct(ident))
error(e.loc, "no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident.toChars(), mt.toChars(), mt.toChars(),
error(errLoc, "no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident.toChars(), mt.toChars(), mt.toChars(),
ns.toChars());
else
error(e.loc, "no property `%s` for type `%s`", ident.toChars(),
error(errLoc, "no property `%s` for type `%s`", ident.toChars(),
mt.toChars());

errorSupplemental(mt.sym.loc, "%s `%s` defined here",
Expand All @@ -7029,7 +7032,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
// https://issues.dlang.org/show_bug.cgi?id=12543
if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
{
return mt.Type.getProperty(sc, e.loc, ident, 0);
return mt.Type.getProperty(sc, e.loc, ident, 0, null, identLoc);
}

/* If e.tupleof
Expand Down Expand Up @@ -7090,7 +7093,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
{
if (e.op == EXP.type)
{
return mt.Type.getProperty(sc, e.loc, ident, 0);
return mt.Type.getProperty(sc, e.loc, ident, 0, null, identLoc);
}
e = new DotTypeExp(e.loc, e, mt.sym);
e = e.expressionSemantic(sc);
Expand All @@ -7100,7 +7103,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
{
if (e.op == EXP.type)
{
return mt.Type.getProperty(sc, e.loc, ident, 0);
return mt.Type.getProperty(sc, e.loc, ident, 0, null, identLoc);
}
if (auto ifbase = cbase.isInterfaceDeclaration())
e = new CastExp(e.loc, e, ifbase.type);
Expand Down
18 changes: 18 additions & 0 deletions compiler/test/fail_compilation/diag21284.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Fix for issue 21284: "no property" error should point at the identifier, not the dot.
* The error location should be on the line of the undefined identifier (`three`), not the dot.
TEST_OUTPUT:
---
fail_compilation/diag21284.d(17): Error: no property `three` for type `E`
fail_compilation/diag21284.d(10): enum `E` defined here
---
*/
enum E { one, two }

void main()
{
auto x =
E
.
three;
}
Loading