/** * Semantic analysis of template parameters. * * Copyright: Copyright (C) 1999-2024 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.dinterpret; import dmd.dsymbol; import dmd.dscope; import dmd.dtemplate; import dmd.globals; import dmd.location; import dmd.expression; import dmd.expressionsem; import dmd.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 */ 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) scope @safe { 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(TemplateThisParameter ttp) { import dmd.errors; if (!sc.getStructClassScope()) error(ttp.loc, "cannot use `this` outside an aggregate type"); visit(cast(TemplateTypeParameter)ttp); } 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; }