| |
| /* Compiler implementation of the D programming language |
| * Copyright (C) 2009-2019 by The D Language Foundation, All Rights Reserved |
| * written by Walter Bright |
| * http://www.digitalmars.com |
| * Distributed under the Boost Software License, Version 1.0. |
| * http://www.boost.org/LICENSE_1_0.txt |
| * https://github.com/D-Programming-Language/dmd/blob/master/src/aliasthis.c |
| */ |
| |
| #include "root/dsystem.h" |
| |
| #include "mars.h" |
| #include "identifier.h" |
| #include "aliasthis.h" |
| #include "scope.h" |
| #include "aggregate.h" |
| #include "dsymbol.h" |
| #include "mtype.h" |
| #include "declaration.h" |
| #include "tokens.h" |
| |
| Expression *semantic(Expression *e, Scope *sc); |
| |
| Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag) |
| { |
| AggregateDeclaration *ad = isAggregate(e->type); |
| |
| if (ad && ad->aliasthis) |
| { |
| unsigned olderrors = gag ? global.startGagging() : 0; |
| |
| Loc loc = e->loc; |
| Type *tthis = (e->op == TOKtype ? e->type : NULL); |
| e = new DotIdExp(loc, e, ad->aliasthis->ident); |
| e = semantic(e, sc); |
| if (tthis && ad->aliasthis->needThis()) |
| { |
| if (e->op == TOKvar) |
| { |
| if (FuncDeclaration *fd = ((VarExp *)e)->var->isFuncDeclaration()) |
| { |
| // Bugzilla 13009: Support better match for the overloaded alias this. |
| bool hasOverloads = false; |
| if (FuncDeclaration *f = fd->overloadModMatch(loc, tthis, hasOverloads)) |
| { |
| if (!hasOverloads) |
| fd = f; // use exact match |
| e = new VarExp(loc, fd, hasOverloads); |
| e->type = f->type; |
| e = new CallExp(loc, e); |
| goto L1; |
| } |
| } |
| } |
| /* non-@property function is not called inside typeof(), |
| * so resolve it ahead. |
| */ |
| { |
| int save = sc->intypeof; |
| sc->intypeof = 1; // bypass "need this" error check |
| e = resolveProperties(sc, e); |
| sc->intypeof = save; |
| } |
| |
| L1: |
| e = new TypeExp(loc, new TypeTypeof(loc, e)); |
| e = semantic(e, sc); |
| } |
| e = resolveProperties(sc, e); |
| |
| if (gag && global.endGagging(olderrors)) |
| e = NULL; |
| } |
| |
| return e; |
| } |
| |
| AliasThis::AliasThis(Loc loc, Identifier *ident) |
| : Dsymbol(NULL) // it's anonymous (no identifier) |
| { |
| this->loc = loc; |
| this->ident = ident; |
| } |
| |
| Dsymbol *AliasThis::syntaxCopy(Dsymbol *s) |
| { |
| assert(!s); |
| return new AliasThis(loc, ident); |
| } |
| |
| void AliasThis::semantic(Scope *sc) |
| { |
| if (semanticRun != PASSinit) |
| return; |
| |
| if (_scope) |
| { |
| sc = _scope; |
| _scope = NULL; |
| } |
| |
| if (!sc) |
| return; |
| |
| semanticRun = PASSsemantic; |
| |
| Dsymbol *p = sc->parent->pastMixin(); |
| AggregateDeclaration *ad = p->isAggregateDeclaration(); |
| if (!ad) |
| { |
| ::error(loc, "alias this can only be a member of aggregate, not %s %s", |
| p->kind(), p->toChars()); |
| return; |
| } |
| |
| assert(ad->members); |
| Dsymbol *s = ad->search(loc, ident); |
| if (!s) |
| { |
| s = sc->search(loc, ident, NULL); |
| if (s) |
| ::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars()); |
| else |
| ::error(loc, "undefined identifier %s", ident->toChars()); |
| return; |
| } |
| else if (ad->aliasthis && s != ad->aliasthis) |
| { |
| ::error(loc, "there can be only one alias this"); |
| return; |
| } |
| |
| if (ad->type->ty == Tstruct && ((TypeStruct *)ad->type)->sym != ad) |
| { |
| AggregateDeclaration *ad2 = ((TypeStruct *)ad->type)->sym; |
| assert(ad2->type == Type::terror); |
| ad->aliasthis = ad2->aliasthis; |
| return; |
| } |
| |
| /* disable the alias this conversion so the implicit conversion check |
| * doesn't use it. |
| */ |
| ad->aliasthis = NULL; |
| |
| Dsymbol *sx = s; |
| if (sx->isAliasDeclaration()) |
| sx = sx->toAlias(); |
| Declaration *d = sx->isDeclaration(); |
| if (d && !d->isTupleDeclaration()) |
| { |
| Type *t = d->type; |
| assert(t); |
| if (ad->type->implicitConvTo(t) > MATCHnomatch) |
| { |
| ::error(loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars()); |
| } |
| } |
| |
| ad->aliasthis = s; |
| semanticRun = PASSsemanticdone; |
| } |
| |
| const char *AliasThis::kind() const |
| { |
| return "alias this"; |
| } |