1 /** 2 * Semantic analysis of template parameters. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templateparamsem.d, _templateparamsem.d) 8 * Documentation: https://dlang.org/phobos/dmd_templateparamsem.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/templateparamsem.d 10 */ 11 12 module dmd.templateparamsem; 13 14 import dmd.arraytypes; 15 import dmd.dinterpret; 16 import dmd.dsymbol; 17 import dmd.dscope; 18 import dmd.dtemplate; 19 import dmd.globals; 20 import dmd.location; 21 import dmd.expression; 22 import dmd.expressionsem; 23 import dmd.rootobject; 24 import dmd.mtype; 25 import dmd.typesem; 26 import dmd.visitor; 27 28 /************************************************ 29 * Performs semantic on TemplateParameter AST nodes. 30 * 31 * Params: 32 * tp = element of `parameters` to be semantically analyzed 33 * sc = context 34 * parameters = array of `TemplateParameters` supplied to the `TemplateDeclaration` 35 * Returns: 36 * `true` if no errors 37 */ 38 extern(C++) bool tpsemantic(TemplateParameter tp, Scope* sc, TemplateParameters* parameters) 39 { 40 scope v = new TemplateParameterSemanticVisitor(sc, parameters); 41 tp.accept(v); 42 return v.result; 43 } 44 45 46 private extern (C++) final class TemplateParameterSemanticVisitor : Visitor 47 { 48 alias visit = Visitor.visit; 49 50 Scope* sc; 51 TemplateParameters* parameters; 52 bool result; 53 54 this(Scope* sc, TemplateParameters* parameters) scope @safe 55 { 56 this.sc = sc; 57 this.parameters = parameters; 58 } 59 60 override void visit(TemplateTypeParameter ttp) 61 { 62 //printf("TemplateTypeParameter.semantic('%s')\n", ident.toChars()); 63 if (ttp.specType && !reliesOnTident(ttp.specType, parameters)) 64 { 65 ttp.specType = ttp.specType.typeSemantic(ttp.loc, sc); 66 } 67 version (none) 68 { 69 // Don't do semantic() until instantiation 70 if (ttp.defaultType) 71 { 72 ttp.defaultType = ttp.defaultType.typeSemantic(ttp.loc, sc); 73 } 74 } 75 result = !(ttp.specType && isError(ttp.specType)); 76 } 77 78 override void visit(TemplateThisParameter ttp) 79 { 80 import dmd.errors; 81 82 if (!sc.getStructClassScope()) 83 error(ttp.loc, "cannot use `this` outside an aggregate type"); 84 visit(cast(TemplateTypeParameter)ttp); 85 } 86 87 override void visit(TemplateValueParameter tvp) 88 { 89 tvp.valType = tvp.valType.typeSemantic(tvp.loc, sc); 90 version (none) 91 { 92 // defer semantic analysis to arg match 93 if (tvp.specValue) 94 { 95 Expression e = tvp.specValue; 96 sc = sc.startCTFE(); 97 e = e.semantic(sc); 98 sc = sc.endCTFE(); 99 e = e.implicitCastTo(sc, tvp.valType); 100 e = e.ctfeInterpret(); 101 if (e.op == EXP.int64 || e.op == EXP.float64 || 102 e.op == EXP.complex80 || e.op == EXP.null_ || e.op == EXP.string_) 103 tvp.specValue = e; 104 } 105 106 if (tvp.defaultValue) 107 { 108 Expression e = defaultValue; 109 sc = sc.startCTFE(); 110 e = e.semantic(sc); 111 sc = sc.endCTFE(); 112 e = e.implicitCastTo(sc, tvp.valType); 113 e = e.ctfeInterpret(); 114 if (e.op == EXP.int64) 115 tvp.defaultValue = e; 116 } 117 } 118 result = !isError(tvp.valType); 119 } 120 121 override void visit(TemplateAliasParameter tap) 122 { 123 if (tap.specType && !reliesOnTident(tap.specType, parameters)) 124 { 125 tap.specType = tap.specType.typeSemantic(tap.loc, sc); 126 } 127 tap.specAlias = aliasParameterSemantic(tap.loc, sc, tap.specAlias, parameters); 128 version (none) 129 { 130 // Don't do semantic() until instantiation 131 if (tap.defaultAlias) 132 tap.defaultAlias = tap.defaultAlias.semantic(tap.loc, sc); 133 } 134 result = !(tap.specType && isError(tap.specType)) && !(tap.specAlias && isError(tap.specAlias)); 135 } 136 137 override void visit(TemplateTupleParameter ttp) 138 { 139 result = true; 140 } 141 } 142 143 /*********************************************** 144 * Support function for performing semantic analysis on `TemplateAliasParameter`. 145 * 146 * Params: 147 * loc = location (for error messages) 148 * sc = context 149 * o = object to run semantic() on, the `TemplateAliasParameter`s `specAlias` or `defaultAlias` 150 * parameters = array of `TemplateParameters` supplied to the `TemplateDeclaration` 151 * Returns: 152 * object resulting from running `semantic` on `o` 153 */ 154 RootObject aliasParameterSemantic(Loc loc, Scope* sc, RootObject o, TemplateParameters* parameters) 155 { 156 if (!o) 157 return null; 158 159 Expression ea = isExpression(o); 160 RootObject eaCTFE() 161 { 162 sc = sc.startCTFE(); 163 ea = ea.expressionSemantic(sc); 164 sc = sc.endCTFE(); 165 return ea.ctfeInterpret(); 166 } 167 Type ta = isType(o); 168 if (ta && (!parameters || !reliesOnTident(ta, parameters))) 169 { 170 Dsymbol s = ta.toDsymbol(sc); 171 if (s) 172 return s; 173 else if (TypeInstance ti = ta.isTypeInstance()) 174 { 175 Type t; 176 const errors = global.errors; 177 ta.resolve(loc, sc, ea, t, s); 178 // if we had an error evaluating the symbol, suppress further errors 179 if (!t && errors != global.errors) 180 return Type.terror; 181 // We might have something that looks like a type 182 // but is actually an expression or a dsymbol 183 // see https://issues.dlang.org/show_bug.cgi?id=16472 184 if (t) 185 return t.typeSemantic(loc, sc); 186 else if (ea) 187 { 188 return eaCTFE(); 189 } 190 else if (s) 191 return s; 192 else 193 assert(0); 194 } 195 else 196 return ta.typeSemantic(loc, sc); 197 } 198 else if (ea) 199 return eaCTFE(); 200 return o; 201 }