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 }