Skip to content

Commit

Permalink
Merge pull request #5690 from 9rnsr/fix13242
Browse files Browse the repository at this point in the history
Issue 13242 - imported aliases should be analyzed lazily
  • Loading branch information
WalterBright committed Apr 22, 2016
2 parents 24b214b + a0e89b1 commit e2dfb4a
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 18 deletions.
29 changes: 29 additions & 0 deletions changelog.dd
Expand Up @@ -8,12 +8,41 @@ $(BUGSTITLE Language Changes,
)

$(BUGSTITLE Compiler Changes,
$(LI $(RELATIVE_LINK2 deferred_alias, Analysis for aliases in imported modules is deferred.))
)

$(BUGSTITLE Language Changes,
)

$(BUGSTITLE Compiler Changes,
$(LI $(LNAME2 deferred_alias, Analysis for aliases in imported modules is deferred.)

$(P Example:)

---
module lib;
template ExpensiveApiImpl(int ver)
{
...
void func() {}
pragma(msg, "instantiated ExpensiveApiImpl ", ver);
}
alias api1 = ExpensiveApiImpl!(1);
alias api2 = ExpensiveApiImpl!(2);
---

---
import lib;
void main()
{
// OK, prints "instantiated ExpensiveApiImpl 1"
api1.func();

// Don't print "instantiated ExpensiveApiImpl 2", because
// the alias name 'api2' is not used.
}
---
)
)

Macros:
Expand Down
51 changes: 35 additions & 16 deletions src/declaration.d
Expand Up @@ -542,6 +542,22 @@ public:
}

override void semantic(Scope* sc)
{
if (semanticRun >= PASSsemanticdone)
return;
assert(semanticRun <= PASSsemantic);

storage_class |= sc.stc & STCdeprecated;
protection = sc.protection;
userAttribDecl = sc.userAttribDecl;

if (!sc.func && inNonRoot())
return;

aliasSemantic(sc);
}

final void aliasSemantic(Scope* sc)
{
//printf("AliasDeclaration::semantic() %s\n", toChars());
if (aliassym)
Expand Down Expand Up @@ -574,10 +590,6 @@ public:
}
inuse = 1;

storage_class |= sc.stc & STCdeprecated;
protection = sc.protection;
userAttribDecl = sc.userAttribDecl;

// Given:
// alias foo.bar.abc def;
// it is not knowable from the syntax whether this is an alias
Expand Down Expand Up @@ -799,24 +811,31 @@ public:
type = Type.terror;
return aliassym;
}
if (aliassym)

if (semanticRun >= PASSsemanticdone)
{
// semantic is already done.

// Even if type.deco !is null, "alias T = const int;` needs semantic
// call to take the storage class `const` as type qualifier.
}
else if (_import && _import._scope)
{
/* If this is an internal alias for selective/renamed import,
* resolve it under the correct scope.
*/
_import.semantic(null);
// Do not see aliassym !is null, because of lambda aliases.

// Do not see type.deco !is null, even so "alias T = const int;` needs
// semantic analysis to take the storage class `const` as type qualifier.
}
else if (_scope)
else
{
semantic(_scope);
if (_import && _import._scope)
{
/* If this is an internal alias for selective/renamed import,
* load the module first.
*/
_import.semantic(null);
}
if (_scope)
{
aliasSemantic(_scope);
}
}

inuse = 1;
Dsymbol s = aliassym ? aliassym.toAlias() : this;
inuse = 0;
Expand Down
1 change: 1 addition & 0 deletions src/declaration.h
Expand Up @@ -205,6 +205,7 @@ class AliasDeclaration : public Declaration
AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s);
Dsymbol *syntaxCopy(Dsymbol *);
void semantic(Scope *sc);
void aliasSmantic(Scope *sc);
bool overloadInsert(Dsymbol *s);
const char *kind();
Type *getType();
Expand Down
5 changes: 5 additions & 0 deletions src/dimport.d
Expand Up @@ -291,6 +291,7 @@ public:
//printf("module4 %s because of %s\n", sc.module.toChars(), mod.toChars());
sc._module.needmoduleinfo = 1;
}

sc = sc.push(mod);
sc.protection = protection;
for (size_t i = 0; i < aliasdecls.dim; i++)
Expand All @@ -300,6 +301,9 @@ public:
if (mod.search(loc, names[i]))
{
ad.semantic(sc);
// If the import declaration is in non-root module,
// analysis of the aliased symbol is deferred.
// Therefore, don't see the ad.aliassym or ad.type here.
}
else
{
Expand All @@ -313,6 +317,7 @@ public:
}
sc = sc.pop();
}

// object self-imports itself, so skip that (Bugzilla 7547)
// don't list pseudo modules __entrypoint.d, __main.d (Bugzilla 11117, 11164)
if (global.params.moduleDeps !is null && !(id == Id.object && sc._module.ident == Id.object) && sc._module.ident != Id.entrypoint && strcmp(sc._module.ident.string, "__main") != 0)
Expand Down
4 changes: 2 additions & 2 deletions src/dsymbol.d
Expand Up @@ -1016,11 +1016,11 @@ public:
Dsymbol s = parent;
for (; s; s = s.toParent())
{
if (TemplateInstance ti = s.isTemplateInstance())
if (auto ti = s.isTemplateInstance())
{
return false;
}
if (Module m = s.isModule())
if (auto m = s.isModule())
{
if (!m.isRoot())
return true;
Expand Down
19 changes: 19 additions & 0 deletions test/compilable/imports/test13242a.d
@@ -0,0 +1,19 @@
module imports.test13242a;

template expensiveArgs(alias v)
{
pragma(msg, "a.expensiveArgs: ", v);
}

template expensiveTemplate(Args...)
{
pragma(msg, "a.expensiveTemplate: ", Args[0]);
}

alias apiSym1 = expensiveTemplate!(1, expensiveArgs!(1));

alias apiSym2 = expensiveTemplate!(2, expensiveArgs!(2));

public import imports.test13242b : apiSym3;

void cheapFunc() {}
13 changes: 13 additions & 0 deletions test/compilable/imports/test13242b.d
@@ -0,0 +1,13 @@
module imports.test13242b;

template expensiveArgs(alias v)
{
pragma(msg, "b.expensiveArgs: ", v);
}

template expensiveTemplate(Args...)
{
pragma(msg, "b.expensiveTemplate: ", Args[0]);
}

alias apiSym3 = expensiveTemplate!(3, expensiveArgs!(3));
34 changes: 34 additions & 0 deletions test/compilable/test13242.d
@@ -0,0 +1,34 @@
// REQUIRED_ARGS: -o-
/*
TEST_OUTPUT:
---
main
+alias apiSym1
a.expensiveArgs: 1
a.expensiveTemplate: 1
-alias apiSym1
+alias apiSym3
b.expensiveArgs: 3
b.expensiveTemplate: 3
-alias apiSym3
---
*/

import imports.test13242a;

void main()
{
pragma(msg, "main");

cheapFunc();

pragma(msg, "+alias apiSym1");
alias apiSym1 = .apiSym1;
pragma(msg, "-alias apiSym1");

// imports.test13242a.apiSym2 is not analyzed.

pragma(msg, "+alias apiSym3");
alias apiSym3 = .apiSym3;
pragma(msg, "-alias apiSym3");
}

0 comments on commit e2dfb4a

Please sign in to comment.