| /** | |
| * Semantic analysis of template parameters. | |
| * | |
| * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved | |
| * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) | |
| * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) | |
| * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templateparamsem.d, _templateparamsem.d) | |
| * Documentation: https://dlang.org/phobos/dmd_templateparamsem.html | |
| * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/templateparamsem.d | |
| */ | |
| module dmd.templateparamsem; | |
| import dmd.arraytypes; | |
| import dmd.dsymbol; | |
| import dmd.dscope; | |
| import dmd.dtemplate; | |
| import dmd.globals; | |
| import dmd.expression; | |
| import dmd.expressionsem; | |
| import dmd.root.rootobject; | |
| import dmd.mtype; | |
| import dmd.typesem; | |
| import dmd.visitor; | |
| /************************************************ | |
| * Performs semantic on TemplateParameter AST nodes. | |
| * | |
| * Params: | |
| * tp = element of `parameters` to be semantically analyzed | |
| * sc = context | |
| * parameters = array of `TemplateParameters` supplied to the `TemplateDeclaration` | |
| * Returns: | |
| * `true` if no errors | |
| */ | |
| extern(C++) bool tpsemantic(TemplateParameter tp, Scope* sc, TemplateParameters* parameters) | |
| { | |
| scope v = new TemplateParameterSemanticVisitor(sc, parameters); | |
| tp.accept(v); | |
| return v.result; | |
| } | |
| private extern (C++) final class TemplateParameterSemanticVisitor : Visitor | |
| { | |
| alias visit = Visitor.visit; | |
| Scope* sc; | |
| TemplateParameters* parameters; | |
| bool result; | |
| this(Scope* sc, TemplateParameters* parameters) | |
| { | |
| this.sc = sc; | |
| this.parameters = parameters; | |
| } | |
| override void visit(TemplateTypeParameter ttp) | |
| { | |
| //printf("TemplateTypeParameter.semantic('%s')\n", ident.toChars()); | |
| if (ttp.specType && !reliesOnTident(ttp.specType, parameters)) | |
| { | |
| ttp.specType = ttp.specType.typeSemantic(ttp.loc, sc); | |
| } | |
| version (none) | |
| { | |
| // Don't do semantic() until instantiation | |
| if (ttp.defaultType) | |
| { | |
| ttp.defaultType = ttp.defaultType.typeSemantic(ttp.loc, sc); | |
| } | |
| } | |
| result = !(ttp.specType && isError(ttp.specType)); | |
| } | |
| override void visit(TemplateValueParameter tvp) | |
| { | |
| tvp.valType = tvp.valType.typeSemantic(tvp.loc, sc); | |
| version (none) | |
| { | |
| // defer semantic analysis to arg match | |
| if (tvp.specValue) | |
| { | |
| Expression e = tvp.specValue; | |
| sc = sc.startCTFE(); | |
| e = e.semantic(sc); | |
| sc = sc.endCTFE(); | |
| e = e.implicitCastTo(sc, tvp.valType); | |
| e = e.ctfeInterpret(); | |
| if (e.op == EXP.int64 || e.op == EXP.float64 || | |
| e.op == EXP.complex80 || e.op == EXP.null_ || e.op == EXP.string_) | |
| tvp.specValue = e; | |
| } | |
| if (tvp.defaultValue) | |
| { | |
| Expression e = defaultValue; | |
| sc = sc.startCTFE(); | |
| e = e.semantic(sc); | |
| sc = sc.endCTFE(); | |
| e = e.implicitCastTo(sc, tvp.valType); | |
| e = e.ctfeInterpret(); | |
| if (e.op == EXP.int64) | |
| tvp.defaultValue = e; | |
| } | |
| } | |
| result = !isError(tvp.valType); | |
| } | |
| override void visit(TemplateAliasParameter tap) | |
| { | |
| if (tap.specType && !reliesOnTident(tap.specType, parameters)) | |
| { | |
| tap.specType = tap.specType.typeSemantic(tap.loc, sc); | |
| } | |
| tap.specAlias = aliasParameterSemantic(tap.loc, sc, tap.specAlias, parameters); | |
| version (none) | |
| { | |
| // Don't do semantic() until instantiation | |
| if (tap.defaultAlias) | |
| tap.defaultAlias = tap.defaultAlias.semantic(tap.loc, sc); | |
| } | |
| result = !(tap.specType && isError(tap.specType)) && !(tap.specAlias && isError(tap.specAlias)); | |
| } | |
| override void visit(TemplateTupleParameter ttp) | |
| { | |
| result = true; | |
| } | |
| } | |
| /*********************************************** | |
| * Support function for performing semantic analysis on `TemplateAliasParameter`. | |
| * | |
| * Params: | |
| * loc = location (for error messages) | |
| * sc = context | |
| * o = object to run semantic() on, the `TemplateAliasParameter`s `specAlias` or `defaultAlias` | |
| * parameters = array of `TemplateParameters` supplied to the `TemplateDeclaration` | |
| * Returns: | |
| * object resulting from running `semantic` on `o` | |
| */ | |
| RootObject aliasParameterSemantic(Loc loc, Scope* sc, RootObject o, TemplateParameters* parameters) | |
| { | |
| if (!o) | |
| return null; | |
| Expression ea = isExpression(o); | |
| RootObject eaCTFE() | |
| { | |
| sc = sc.startCTFE(); | |
| ea = ea.expressionSemantic(sc); | |
| sc = sc.endCTFE(); | |
| return ea.ctfeInterpret(); | |
| } | |
| Type ta = isType(o); | |
| if (ta && (!parameters || !reliesOnTident(ta, parameters))) | |
| { | |
| Dsymbol s = ta.toDsymbol(sc); | |
| if (s) | |
| return s; | |
| else if (TypeInstance ti = ta.isTypeInstance()) | |
| { | |
| Type t; | |
| const errors = global.errors; | |
| ta.resolve(loc, sc, ea, t, s); | |
| // if we had an error evaluating the symbol, suppress further errors | |
| if (!t && errors != global.errors) | |
| return Type.terror; | |
| // We might have something that looks like a type | |
| // but is actually an expression or a dsymbol | |
| // see https://issues.dlang.org/show_bug.cgi?id=16472 | |
| if (t) | |
| return t.typeSemantic(loc, sc); | |
| else if (ea) | |
| { | |
| return eaCTFE(); | |
| } | |
| else if (s) | |
| return s; | |
| else | |
| assert(0); | |
| } | |
| else | |
| return ta.typeSemantic(loc, sc); | |
| } | |
| else if (ea) | |
| return eaCTFE(); | |
| return o; | |
| } |