Skip to content

Commit

Permalink
[Refactoring] TemplateInstance::semantic()
Browse files Browse the repository at this point in the history
- Remove a goto jump
- Reduce code indent level
- Use ModToStc in TemplateThisParameter resolution
  • Loading branch information
9rnsr committed Sep 5, 2014
1 parent 1ea942a commit 5c44275
Showing 1 changed file with 116 additions and 145 deletions.
261 changes: 116 additions & 145 deletions src/template.c
Expand Up @@ -223,11 +223,11 @@ bool definitelyValueParameter(Expression *e)
if (e->op != TOKdotvar)
return true;

/* Template instantiations involving a DotVar expression are difficult.
* In most cases, they should be treated as a value parameter, and interpreted.
* But they might also just be a fully qualified name, which should be treated
* as an alias.
*/
/* Template instantiations involving a DotVar expression are difficult.
* In most cases, they should be treated as a value parameter, and interpreted.
* But they might also just be a fully qualified name, which should be treated
* as an alias.
*/

// x.y.f cannot be a value
FuncDeclaration *f = ((DotVarExp *)e)->var->isFuncDeclaration();
Expand Down Expand Up @@ -5842,10 +5842,6 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs)
return;
}

/* If a TemplateInstance is ever instantiated by non-root modules,
* we do not have to generate code for it,
* because it will be generated when the non-root module is compiled.
*/
Module *mi = sc->instantiatingModule();
if (!instantiatingModule || instantiatingModule->isRoot())
instantiatingModule = mi;
Expand Down Expand Up @@ -5904,160 +5900,137 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs)
/* See if there is an existing TemplateInstantiation that already
* implements the typeargs. If so, just refer to that one instead.
*/
inst = tempdecl->findExistingInstance(this, fargs);
if (!inst)
{
// So, we need to implement 'this' instance.
}
else if (inst->gagged && !gagged && inst->errors)
{
TemplateInstance *ti = tempdecl->findExistingInstance(this, fargs);
if (ti)
// If the first instantiation had failed, re-run semantic,
// so that error messages are shown.
}
else
{
// It's a match
parent = inst->parent;
errors = inst->errors;

// If both this and the previous instantiation were gagged,
// use the number of errors that happened last time.
if (inst->gagged && gagged)
{
// It's a match
inst = ti;
parent = ti->parent;
global.errors += inst->errors;
global.gaggedErrors += inst->errors;
}

// If both this and the previous instantiation were gagged,
// use the number of errors that happened last time.
if (inst->gagged && gagged)
{
global.errors += inst->errors;
global.gaggedErrors += inst->errors;
}
// If the first instantiation was gagged, but this is not:
if (inst->gagged && !gagged)
{
// It had succeeded, mark it is a non-gagged instantiation,
// and reuse it.
inst->gagged = false;
}

// If the first instantiation was gagged, but this is not:
if (inst->gagged && !gagged)
{
// If the first instantiation had failed, re-run semantic,
// so that error messages are shown.
if (inst->errors)
goto L1;
// It had succeeded, mark it is a non-gagged instantiation,
// and reuse it.
inst->gagged = false;
}
// If the first instantiation was speculative, but this is not:
if (inst->speculative && !sc->speculative)
{
// Mark it is a non-speculative instantiation.
inst->speculative = false;

// If the first instantiation was speculative, but this is not:
if (inst->speculative && !sc->speculative)
{
// Mark it is a non-speculative instantiation.
inst->speculative = false;
// Bugzilla 13400: When an instance is changed to non-speculative,
// its instantiatingModule should also be updated.
// See test/runnable/link13400.d
inst->instantiatingModule = mi;
}

// Bugzilla 13400: When an instance is changed to non-speculative,
// its instantiatingModule should also be updated.
// See test/runnable/link13400.d
inst->instantiatingModule = mi;
}
// If the first instantiation was in speculative context, but this is not:
if (!inst->tinst && inst->speculative &&
tinst && !(sc->flags & (SCOPEconstraint | SCOPEcompile)))
{
// Reconnect the chain if this instantiation is not in speculative context.
TemplateInstance *tix = tinst;
while (tix && tix != inst)
tix = tix->tinst;
if (tix != inst) // Bugzilla 13379: Prevent circular chain
inst->tinst = tinst;
}

// If the first instantiation was in speculative context, but this is not:
if (!inst->tinst && inst->speculative &&
tinst && !(sc->flags & (SCOPEconstraint | SCOPEcompile)))
{
// Reconnect the chain if this instantiation is not in speculative context.
TemplateInstance *tix = tinst;
while (tix && tix != inst)
tix = tix->tinst;
if (tix != inst) // Bugzilla 13379: Prevent circular chain
inst->tinst = tinst;
}
if (!inst->instantiatingModule || inst->instantiatingModule->isRoot())
inst->instantiatingModule = mi;

#if LOG
printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun);
printf("\tit's a match with instance %p, %d\n", inst, inst->semanticRun);
#endif
if (!inst->instantiatingModule || inst->instantiatingModule->isRoot())
inst->instantiatingModule = mi;
errors = inst->errors;
return;
}
L1: ;
return;
}

/* So, we need to implement 'this' instance.
*/
#if LOG
printf("\timplement template instance %s '%s'\n", tempdecl->parent->toChars(), toChars());
printf("\ttempdecl %s\n", tempdecl->toChars());
#endif
unsigned errorsave = global.errors;
inst = this;

TemplateInstance *tempdecl_instance_idx = tempdecl->addInstance(this);

inst = this;
parent = enclosing ? enclosing : tempdecl->parent;
//printf("parent = '%s'\n", parent->kind());

TemplateInstance *tempdecl_instance_idx = tempdecl->addInstance(this);

//getIdent();

// Add 'this' to the enclosing scope's members[] so the semantic routines
// will get called on the instance members. Store the place we added it to
// in target_symbol_list(_idx) so we can remove it later if we encounter
// an error.
#if 1
Dsymbols *target_symbol_list = NULL;
Dsymbols *target_symbol_list;
size_t target_symbol_list_idx = 0;
//if (sc->scopesym) printf("3: sc is %s %s\n", sc->scopesym->kind(), sc->scopesym->toChars());
if (sc->scopesym && sc->scopesym->members && !sc->scopesym->isTemplateMixin())
{
/* A module can have explicit template instance and its alias
* in module scope (e,g, `alias Base64Impl!('+', '/') Base64;`).
* When the module is just imported, compiler can assume that
* its instantiated code would be contained in the separately compiled
* obj/lib file (e.g. phobos.lib). So we can omit their semantic3 running.
*/
//if (sc->scopesym->isModule())
// printf("module level instance %s\n", toChars());

//printf("\t1: adding to %s %s\n", sc->scopesym->kind(), sc->scopesym->toChars());
target_symbol_list = sc->scopesym->members;
}
else
{
Dsymbols *a;
Scope *scx = sc;
#if 0
for (scx = sc; scx; scx = scx->enclosing)
if (scx->scopesym)
break;
#endif
Dsymbol *s = enclosing ? enclosing : tempdecl->parent;
while (s && !s->isModule())
s = s->toParent2();
assert(s);
Module *m = (Module *)s;
if (!m->isRoot())
m = m->importedFrom;

//if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars());
/* The problem is if A imports B, and B imports A, and both A
* and B instantiate the same template, does the compilation of A
* or the compilation of B do the actual instantiation?
*
* see bugzilla 2500.
*
* && !scx->module->selfImports()
*/
if (scx && scx->scopesym && scx->scopesym->members &&
!scx->scopesym->isTemplateMixin())
{
/* A module can have explicit template instance and its alias
* in module scope (e,g, `alias Base64Impl!('+', '/') Base64;`).
* When the module is just imported, compiler can assume that
* its instantiated code would be contained in the separately compiled
* obj/lib file (e.g. phobos.lib). So we can omit their semantic3 running.
*/
//if (scx->scopesym->isModule())
// printf("module level instance %s\n", toChars());
//printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars());
target_symbol_list = m->members;

//printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars());
a = scx->scopesym->members;
}
else
/* Defer semantic3 running in order to avoid mutual forward reference.
* See test/runnable/test10736.d
*/
if (m->semanticRun >= PASSsemantic3done)
Module::addDeferredSemantic3(this);
}
for (size_t i = 0; 1; i++)
{
if (i == target_symbol_list->dim)
{
Dsymbol *s = enclosing ? enclosing : tempdecl->parent;
for (; s; s = s->toParent2())
{
if (s->isModule())
break;
}
assert(s);
Module *m = (Module *)s;
if (!m->isRoot())
{
m = m->importedFrom;
}
//printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars());
a = m->members;

/* Defer semantic3 running in order to avoid mutual forward reference.
* See test/runnable/test10736.d
*/
if (m->semanticRun >= PASSsemantic3done)
Module::addDeferredSemantic3(this);
target_symbol_list_idx = i;
target_symbol_list->push(this);
break;
}
for (size_t i = 0; 1; i++)
if (this == (*target_symbol_list)[i]) // if already in Array
{
if (i == a->dim)
{
target_symbol_list = a;
target_symbol_list_idx = i;
a->push(this);
break;
}
if (this == (*a)[i]) // if already in Array
break;
target_symbol_list = NULL;
break;
}
}
#endif
Expand All @@ -6070,28 +6043,14 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs)
else
members = Dsymbol::arraySyntaxCopy(tempdecl->members);

// todo for TemplateThisParameter
// resolve TemplateThisParameter
for (size_t i = 0; i < tempdecl->parameters->dim; i++)
{
if ((*tempdecl->parameters)[i]->isTemplateThisParameter() == NULL)
continue;
Type *t = isType((*tiargs)[i]);
assert(t);

StorageClass stc = 0;
if (t->mod & MODimmutable)
stc |= STCimmutable;
else
{
if (t->mod & MODconst)
stc |= STCconst;
else if (t->mod & MODwild)
stc |= STCwild;

if (t->mod & MODshared)
stc |= STCshared;
}
if (stc != 0)
if (StorageClass stc = ModToStc(t->mod))
{
//printf("t = %s, stc = x%llx\n", t->toChars(), stc);
Dsymbols *s = new Dsymbols();
Expand Down Expand Up @@ -7872,7 +7831,19 @@ bool TemplateInstance::needsCodegen()
{
Module *mi = instantiatingModule;

// If mi imports any root modules, we still need to generate the code.
/* If a TemplateInstance is ever instantiated by non-root modules,
* we do not have to generate code for it,
* because it will be generated when the non-root module is compiled.
*
* But, if mi imports any root modules, we still need to generate the code.
*
* The problem is if A imports B, and B imports A, and both A
* and B instantiate the same template, does the compilation of A
* or the compilation of B do the actual instantiation?
*
* See bugzilla 2500.
*/

for (size_t i = 0; i < Module::amodules.dim; ++i)
{
Module *m = Module::amodules[i];
Expand Down

0 comments on commit 5c44275

Please sign in to comment.