1 /** 2 * Implements the `alias this` symbol. 3 * 4 * Specification: $(LINK2 https://dlang.org/spec/class.html#alias-this, Alias This) 5 * 6 * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d, _aliasthis.d) 10 * Documentation: https://dlang.org/phobos/dmd_aliasthis.html 11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/aliasthis.d 12 */ 13 14 module dmd.aliasthis; 15 16 import core.stdc.stdio; 17 import dmd.aggregate; 18 import dmd.dscope; 19 import dmd.dsymbol; 20 import dmd.expression; 21 import dmd.expressionsem; 22 import dmd.globals; 23 import dmd.identifier; 24 import dmd.mtype; 25 import dmd.opover; 26 import dmd.tokens; 27 import dmd.visitor; 28 29 /*********************************************************** 30 * alias ident this; 31 */ 32 extern (C++) final class AliasThis : Dsymbol 33 { 34 Identifier ident; 35 /// The symbol this `alias this` resolves to 36 Dsymbol sym; 37 /// Whether this `alias this` is deprecated or not 38 bool isDeprecated_; 39 40 extern (D) this(const ref Loc loc, Identifier ident) 41 { 42 super(loc, null); // it's anonymous (no identifier) 43 this.ident = ident; 44 } 45 46 override Dsymbol syntaxCopy(Dsymbol s) 47 { 48 assert(!s); 49 auto at = new AliasThis(loc, ident); 50 at.comment = comment; 51 return at; 52 } 53 54 override const(char)* kind() const 55 { 56 return "alias this"; 57 } 58 59 AliasThis isAliasThis() 60 { 61 return this; 62 } 63 64 override void accept(Visitor v) 65 { 66 v.visit(this); 67 } 68 69 override bool isDeprecated() const 70 { 71 return this.isDeprecated_; 72 } 73 } 74 75 Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false) 76 { 77 for (AggregateDeclaration ad = isAggregate(e.type); ad;) 78 { 79 if (ad.aliasthis) 80 { 81 uint olderrors = gag ? global.startGagging() : 0; 82 Loc loc = e.loc; 83 Type tthis = (e.op == TOK.type ? e.type : null); 84 e = new DotIdExp(loc, e, ad.aliasthis.ident); 85 e = e.expressionSemantic(sc); 86 if (tthis && ad.aliasthis.sym.needThis()) 87 { 88 if (e.op == TOK.variable) 89 { 90 if (auto fd = (cast(VarExp)e).var.isFuncDeclaration()) 91 { 92 // https://issues.dlang.org/show_bug.cgi?id=13009 93 // Support better match for the overloaded alias this. 94 bool hasOverloads; 95 if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads)) 96 { 97 if (!hasOverloads) 98 fd = f; // use exact match 99 e = new VarExp(loc, fd, hasOverloads); 100 e.type = f.type; 101 e = new CallExp(loc, e); 102 goto L1; 103 } 104 } 105 } 106 /* non-@property function is not called inside typeof(), 107 * so resolve it ahead. 108 */ 109 { 110 int save = sc.intypeof; 111 sc.intypeof = 1; // bypass "need this" error check 112 e = resolveProperties(sc, e); 113 sc.intypeof = save; 114 } 115 L1: 116 e = new TypeExp(loc, new TypeTypeof(loc, e)); 117 e = e.expressionSemantic(sc); 118 } 119 e = resolveProperties(sc, e); 120 if (!gag) 121 ad.aliasthis.checkDeprecatedAliasThis(loc, sc); 122 else if (global.endGagging(olderrors)) 123 e = null; 124 } 125 126 import dmd.dclass : ClassDeclaration; 127 auto cd = ad.isClassDeclaration(); 128 if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object) 129 { 130 ad = cd.baseClass; 131 continue; 132 } 133 break; 134 } 135 return e; 136 } 137 138 /** 139 * Check if an `alias this` is deprecated 140 * 141 * Usually one would use `expression.checkDeprecated(scope, aliasthis)` to 142 * check if `expression` uses a deprecated `aliasthis`, but this calls 143 * `toPrettyChars` which lead to the following message: 144 * "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated" 145 * 146 * Params: 147 * at = The `AliasThis` object to check 148 * loc = `Loc` of the expression triggering the access to `at` 149 * sc = `Scope` of the expression 150 * (deprecations do not trigger in deprecated scopes) 151 * 152 * Returns: 153 * Whether the alias this was reported as deprecated. 154 */ 155 bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc) 156 { 157 import dmd.errors : deprecation; 158 import dmd.dsymbolsem : getMessage; 159 160 if (global.params.useDeprecated != DiagnosticReporting.off 161 && at.isDeprecated() && !sc.isDeprecated()) 162 { 163 const(char)* message = null; 164 for (Dsymbol p = at; p; p = p.parent) 165 { 166 message = p.depdecl ? p.depdecl.getMessage() : null; 167 if (message) 168 break; 169 } 170 if (message) 171 deprecation(loc, "`alias %s this` is deprecated - %s", 172 at.sym.toChars(), message); 173 else 174 deprecation(loc, "`alias %s this` is deprecated", 175 at.sym.toChars()); 176 return true; 177 } 178 return false; 179 }