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