Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id) { //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); Dsymbol *s = toAlias(); Dsymbol *sm; if (Declaration *d = s->isDeclaration()) { if (d->inuse) { ::error(loc, "circular reference to '%s'", d->toPrettyChars()); return NULL; } } switch (id->dyncast()) { case DYNCAST_IDENTIFIER: sm = s->search(loc, (Identifier *)id); break; case DYNCAST_DSYMBOL: { // It's a template instance //printf("\ttemplate instance id\n"); Dsymbol *st = (Dsymbol *)id; TemplateInstance *ti = st->isTemplateInstance(); sm = s->search(loc, ti->name); if (!sm) { sm = s->search_correct(ti->name); if (sm) error("template identifier '%s' is not a member of '%s %s', did you mean '%s %s'?", ti->name->toChars(), s->kind(), s->toChars(), sm->kind(), sm->toChars()); else error("template identifier '%s' is not a member of '%s %s'", ti->name->toChars(), s->kind(), s->toChars()); return NULL; } sm = sm->toAlias(); TemplateDeclaration *td = sm->isTemplateDeclaration(); if (!td) { error("%s is not a template, it is a %s", ti->name->toChars(), sm->kind()); return NULL; } ti->tempdecl = td; if (!ti->semanticRun) ti->semantic(sc); sm = ti->toAlias(); break; } default: assert(0); } return sm; }
void AliasThis::semantic(Scope *sc) { Dsymbol *p = sc->parent->pastMixin(); AggregateDeclaration *ad = p->isAggregateDeclaration(); if (!ad) { ::error(loc, "alias this can only be a member of aggregate, not %s %s", p->kind(), p->toChars()); return; } assert(ad->members); Dsymbol *s = ad->search(loc, ident); if (!s) { s = sc->search(loc, ident, NULL); if (s) ::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars()); else ::error(loc, "undefined identifier %s", ident->toChars()); return; } else if (ad->aliasthis && s != ad->aliasthis) { ::error(loc, "there can be only one alias this"); return; } if (ad->type->ty == Tstruct && ((TypeStruct *)ad->type)->sym != ad) { AggregateDeclaration *ad2 = ((TypeStruct *)ad->type)->sym; assert(ad2->type == Type::terror); ad->aliasthis = ad2->aliasthis; return; } /* disable the alias this conversion so the implicit conversion check * doesn't use it. */ ad->aliasthis = NULL; Dsymbol *sx = s; if (sx->isAliasDeclaration()) sx = sx->toAlias(); Declaration *d = sx->isDeclaration(); if (d && !d->isTupleDeclaration()) { Type *t = d->type; assert(t); if (ad->type->implicitConvTo(t) > MATCHnomatch) { ::error(loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars()); } } ad->aliasthis = s; }
Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d)) { int result = 0; if (!e->args || !e->args->dim) goto Lfalse; for (size_t i = 0; i < e->args->dim; i++) { Dsymbol *s = getDsymbol((*e->args)[i]); if (!s) goto Lfalse; Declaration *d = s->isDeclaration(); if (!d || !fp(d)) goto Lfalse; } result = 1; Lfalse: return new IntegerExp(e->loc, result, Type::tbool); }
Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) { //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; // Look in symbols declared in this module Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0); // hide the aliases generated by selective or renamed private imports if (s && flags & 1) if (AliasDeclaration* ad = s->isAliasDeclaration()) // may be a private alias to a function that is overloaded. these // are sorted out during overload resolution, accept them here if (ad->importprot == PROTprivate && !ad->aliassym->isFuncAliasDeclaration()) s = NULL; if (s) { //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); } else if (imports) { // Look in imported modules for (size_t i = 0; i < imports->dim; i++) { Dsymbol *ss = (*imports)[i]; Dsymbol *s2; // If private import, don't search it if (flags & 1 && prots[i] == PROTprivate) continue; //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); /* Don't find private members if ss is a module */ s2 = ss->search(loc, ident, ss->isImport() ? 1 : 0); if (!s) s = s2; else if (s2 && s != s2) { if (s->toAlias() == s2->toAlias()) { /* After following aliases, we found the same symbol, * so it's not an ambiguity. * But if one alias is deprecated, prefer the other. */ if (s->isDeprecated()) s = s2; } else { /* Two imports of the same module should be regarded as * the same. */ Import *i1 = s->isImport(); Import *i2 = s2->isImport(); if (!(i1 && i2 && (i1->mod == i2->mod || (!i1->parent->isImport() && !i2->parent->isImport() && i1->ident->equals(i2->ident)) ) ) ) { ScopeDsymbol::multiplyDefined(loc, s, s2); break; } } } } if (s) { Declaration *d = s->isDeclaration(); if (d && d->protection == PROTprivate && !d->parent->isTemplateMixin()) error(loc, "%s is private", d->toPrettyChars()); } } return s; }
Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) { //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); if (ident == Id::dollar) { VarDeclaration **pvar; Expression *ce; L1: if (td) { /* $ gives the number of elements in the tuple */ VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); Expression *e = new IntegerExp(Loc(), td->objects->dim, Type::tsize_t); v->init = new ExpInitializer(Loc(), e); v->storage_class |= STCstatic | STCconst; v->semantic(sc); return v; } if (type) { /* $ gives the number of type entries in the type tuple */ VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); Expression *e = new IntegerExp(Loc(), type->arguments->dim, Type::tsize_t); v->init = new ExpInitializer(Loc(), e); v->storage_class |= STCstatic | STCconst; v->semantic(sc); return v; } if (exp->op == TOKindex) { /* array[index] where index is some function of $ */ IndexExp *ie = (IndexExp *)exp; pvar = &ie->lengthVar; ce = ie->e1; } else if (exp->op == TOKslice) { /* array[lwr .. upr] where lwr or upr is some function of $ */ SliceExp *se = (SliceExp *)exp; pvar = &se->lengthVar; ce = se->e1; } else if (exp->op == TOKarray) { /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) */ ArrayExp *ae = (ArrayExp *)exp; pvar = &ae->lengthVar; ce = ae->e1; } else /* Didn't find $, look in enclosing scope(s). */ return NULL; while (ce->op == TOKcomma) ce = ((CommaExp *)ce)->e2; /* If we are indexing into an array that is really a type * tuple, rewrite this as an index into a type tuple and * try again. */ if (ce->op == TOKtype) { Type *t = ((TypeExp *)ce)->type; if (t->ty == Ttuple) { type = (TypeTuple *)t; goto L1; } } /* *pvar is lazily initialized, so if we refer to $ * multiple times, it gets set only once. */ if (!*pvar) // if not already initialized { /* Create variable v and set it to the value of $ */ VarDeclaration *v; Type *t; if (ce->op == TOKtuple) { /* It is for an expression tuple, so the * length will be a const. */ Expression *e = new IntegerExp(Loc(), ((TupleExp *)ce)->exps->dim, Type::tsize_t); v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, new ExpInitializer(Loc(), e)); v->storage_class |= STCstatic | STCconst; } else if (ce->type && (t = ce->type->toBasetype()) != NULL && (t->ty == Tstruct || t->ty == Tclass)) { // Look for opDollar assert(exp->op == TOKarray || exp->op == TOKslice); AggregateDeclaration *ad = NULL; if (t->ty == Tclass) { ad = ((TypeClass *)t)->sym; } else if (t->ty == Tstruct) { ad = ((TypeStruct *)t)->sym; } assert(ad); Dsymbol *s = ad->search(loc, Id::opDollar, 0); if (!s) // no dollar exists -- search in higher scope return NULL; s = s->toAlias(); Expression *e = NULL; // Check for multi-dimensional opDollar(dim) template. if (TemplateDeclaration *td = s->isTemplateDeclaration()) { dinteger_t dim; if (exp->op == TOKarray) { dim = ((ArrayExp *)exp)->currentDimension; } else if (exp->op == TOKslice) { dim = 0; // slices are currently always one-dimensional } Objects *tdargs = new Objects(); Expression *edim = new IntegerExp(Loc(), dim, Type::tsize_t); edim = edim->semantic(sc); tdargs->push(edim); //TemplateInstance *ti = new TemplateInstance(loc, td, tdargs); //ti->semantic(sc); e = new DotTemplateInstanceExp(loc, ce, td->ident, tdargs); } else { /* opDollar exists, but it's not a template. * This is acceptable ONLY for single-dimension indexing. * Note that it's impossible to have both template & function opDollar, * because both take no arguments. */ if (exp->op == TOKarray && ((ArrayExp *)exp)->arguments->dim != 1) { exp->error("%s only defines opDollar for one dimension", ad->toChars()); return NULL; } Declaration *d = s->isDeclaration(); assert(d); e = new DotVarExp(loc, ce, d); } e = e->semantic(sc); if (!e->type) exp->error("%s has no value", e->toChars()); t = e->type->toBasetype(); if (t && t->ty == Tfunction) e = new CallExp(e->loc, e); v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(Loc(), e)); } else { /* For arrays, $ will either be a compile-time constant * (in which case its value in set during constant-folding), * or a variable (in which case an expression is created in * toir.c). */ VoidInitializer *e = new VoidInitializer(Loc()); e->type = Type::tsize_t; v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, e); v->storage_class |= STCctfe; // it's never a true static variable } *pvar = v; } (*pvar)->semantic(sc); return (*pvar); } return NULL; }
int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) { if (!arguments || !arguments->dim) return 0; if (sapply) // prefer opApply { for (size_t u = 0; u < arguments->dim; u++) { Parameter *arg = (*arguments)[u]; if (arg->type) { arg->type = arg->type->semantic(loc, sc); arg->type = arg->type->addStorageClass(arg->storageClass); } } Expression *ethis; Type *tab = aggr->type->toBasetype(); if (tab->ty == Tclass || tab->ty == Tstruct) ethis = aggr; else { assert(tab->ty == Tdelegate && aggr->op == TOKdelegate); ethis = ((DelegateExp *)aggr)->e1; } /* Look for like an * int opApply(int delegate(ref Type [, ...]) dg); * overload */ FuncDeclaration *fd = sapply->isFuncDeclaration(); if (fd) { sapply = inferApplyArgTypesX(ethis, fd, arguments); } #if 0 TemplateDeclaration *td = sapply->isTemplateDeclaration(); if (td) { inferApplyArgTypesZ(td, arguments); } #endif return sapply ? 1 : 0; } /* Return if no arguments need types. */ for (size_t u = 0; u < arguments->dim; u++) { Parameter *arg = (*arguments)[u]; if (!arg->type) break; } AggregateDeclaration *ad; Parameter *arg = (*arguments)[0]; Type *taggr = aggr->type; assert(taggr); Type *tab = taggr->toBasetype(); switch (tab->ty) { case Tarray: case Tsarray: case Ttuple: if (arguments->dim == 2) { if (!arg->type) { arg->type = Type::tsize_t; // key type arg->type = arg->type->addStorageClass(arg->storageClass); } arg = (*arguments)[1]; } if (!arg->type && tab->ty != Ttuple) { arg->type = tab->nextOf(); // value type arg->type = arg->type->addStorageClass(arg->storageClass); } break; case Taarray: { TypeAArray *taa = (TypeAArray *)tab; if (arguments->dim == 2) { if (!arg->type) { arg->type = taa->index; // key type arg->type = arg->type->addStorageClass(arg->storageClass); } arg = (*arguments)[1]; } if (!arg->type) { arg->type = taa->next; // value type arg->type = arg->type->addStorageClass(arg->storageClass); } break; } case Tclass: ad = ((TypeClass *)tab)->sym; goto Laggr; case Tstruct: ad = ((TypeStruct *)tab)->sym; goto Laggr; Laggr: if (arguments->dim == 1) { if (!arg->type) { /* Look for a front() or back() overload */ Identifier *id = (op == TOKforeach) ? Id::Ffront : Id::Fback; Dsymbol *s = ad->search(Loc(), id, 0); FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; if (fd) { // Resolve inout qualifier of front type arg->type = fd->type->nextOf(); if (arg->type) { arg->type = arg->type->substWildTo(tab->mod); arg->type = arg->type->addStorageClass(arg->storageClass); } } else if (s && s->isTemplateDeclaration()) ; else if (s && s->isDeclaration()) arg->type = ((Declaration *)s)->type; else break; } break; } break; case Tdelegate: { if (!inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments)) return 0; break; } default: break; // ignore error, caught later } return 1; }
Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) { //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); // Look in symbols declared in this module Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; if (s) { //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); } else if (imports) { OverloadSet *a = NULL; // Look in imported modules for (int i = 0; i < imports->dim; i++) { ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i]; Dsymbol *s2; // If private import, don't search it if (flags & 1 && prots[i] == PROTprivate) continue; //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); /* Don't find private members if ss is a module */ s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); if (!s) s = s2; else if (s2 && s != s2) { if (s->toAlias() == s2->toAlias()) { /* After following aliases, we found the same symbol, * so it's not an ambiguity. * But if one alias is deprecated, prefer the other. */ if (s->isDeprecated()) s = s2; } else { /* Two imports of the same module should be regarded as * the same. */ Import *i1 = s->isImport(); Import *i2 = s2->isImport(); if (!(i1 && i2 && (i1->mod == i2->mod || (!i1->parent->isImport() && !i2->parent->isImport() && i1->ident->equals(i2->ident)) ) ) ) { /* If both s2 and s are overloadable (though we only * need to check s once) */ if (s2->isOverloadable() && (a || s->isOverloadable())) { if (!a) a = new OverloadSet(); /* Don't add to a[] if s2 is alias of previous sym */ for (int j = 0; j < a->a.dim; j++) { Dsymbol *s3 = (Dsymbol *)a->a.data[j]; if (s2->toAlias() == s3->toAlias()) { if (s3->isDeprecated()) a->a.data[j] = (void *)s2; goto Lcontinue; } } a->push(s2); Lcontinue: continue; } if (flags & 4) // if return NULL on ambiguity return NULL; if (!(flags & 2)) ss->multiplyDefined(loc, s, s2); break; } } } } /* Build special symbol if we had multiple finds */ if (a) { assert(s); a->push(s); s = a; } if (s) { Declaration *d = s->isDeclaration(); /* if (d && d->protection == PROTprivate && !d->parent->isTemplateMixin() && !(flags & 2)) error("%s is private", d->toPrettyChars()); */ } } return s; }
Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) { //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; // Look in symbols declared in this module Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0); if (s) { //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); } else if (imports) { OverloadSet *a = NULL; // Look in imported modules for (size_t i = 0; i < imports->dim; i++) { Dsymbol *ss = (*imports)[i]; Dsymbol *s2; // If private import, don't search it if (flags & 1 && prots[i] == PROTprivate) continue; //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); /* Don't find private members if ss is a module */ s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); if (!s) s = s2; else if (s2 && s != s2) { if (s->toAlias() == s2->toAlias() || s->getType() == s2->getType() && s->getType()) { /* After following aliases, we found the same * symbol, so it's not an ambiguity. But if one * alias is deprecated or less accessible, prefer * the other. */ if (s->isDeprecated() || s2->prot() > s->prot() && s2->prot() != PROTnone) s = s2; } else { /* Two imports of the same module should be regarded as * the same. */ Import *i1 = s->isImport(); Import *i2 = s2->isImport(); if (!(i1 && i2 && (i1->mod == i2->mod || (!i1->parent->isImport() && !i2->parent->isImport() && i1->ident->equals(i2->ident)) ) ) ) { /* Bugzilla 8668: * Public selective import adds AliasDeclaration in module. * To make an overload set, resolve aliases in here and * get actual overload roots which accessible via s and s2. */ s = s->toAlias(); s2 = s2->toAlias(); /* If both s2 and s are overloadable (though we only * need to check s once) */ if (s2->isOverloadable() && (a || s->isOverloadable())) { if (!a) a = new OverloadSet(s->ident); /* Don't add to a[] if s2 is alias of previous sym */ for (size_t j = 0; j < a->a.dim; j++) { Dsymbol *s3 = a->a[j]; if (s2->toAlias() == s3->toAlias()) { if (s3->isDeprecated() || s2->prot() > s3->prot() && s2->prot() != PROTnone) a->a[j] = s2; goto Lcontinue; } } a->push(s2); Lcontinue: continue; } if (flags & 4) // if return NULL on ambiguity return NULL; if (!(flags & 2)) ScopeDsymbol::multiplyDefined(loc, s, s2); break; } } } } /* Build special symbol if we had multiple finds */ if (a) { assert(s); a->push(s); s = a; } if (s) { if (!(flags & 2)) { Declaration *d = s->isDeclaration(); if (d && d->protection == PROTprivate && !d->parent->isTemplateMixin()) error(loc, "%s is private", d->toPrettyChars()); AggregateDeclaration *ad = s->isAggregateDeclaration(); if (ad && ad->protection == PROTprivate && !ad->parent->isTemplateMixin()) error(loc, "%s is private", ad->toPrettyChars()); EnumDeclaration *ed = s->isEnumDeclaration(); if (ed && ed->protection == PROTprivate && !ed->parent->isTemplateMixin()) error(loc, "%s is private", ed->toPrettyChars()); TemplateDeclaration *td = s->isTemplateDeclaration(); if (td && td->protection == PROTprivate && !td->parent->isTemplateMixin()) error(loc, "%s is private", td->toPrettyChars()); } } } return s; }