bool SymbolRegistry::lookupSymbol(SymbolScope* scope, const std::wstring& name, SymbolScope** container, SymbolPtr* ret, bool lazyResolve) { SymbolScope* s = scope; for(; s; s = s->parent) { SymbolPtr symbol = s->lookup(name, lazyResolve); if(symbol) { if(container) *container = s; if(ret) *ret = symbol; return true; } } return false; }
void SemanticAnalyzer::visitValueBinding(const ValueBindingPtr& node) { PatternPtr name = node->getName(); //tuple was already exploded in declaration analyzer if(name->getNodeType() == NodeType::Tuple) { validateTupleTypeDeclaration(node); } if (name->getNodeType() != NodeType::Identifier) return; if(node->getOwner()->isReadOnly() && !node->getInitializer() && ctx->currentType == nullptr) { error(node, Errors::E_LET_REQUIRES_INITIALIZER); return; } //handle type inference for temporary variable if(node->isTemporary() && node->getInitializer()) { //temporary variable always has an initializer TypePtr initializerType; TypePtr declaredType = node->getType(); SCOPED_SET(ctx->contextualType, declaredType); node->getInitializer()->accept(this); initializerType = node->getInitializer()->getType(); assert(initializerType != nullptr); if(declaredType) { //it has both type definition and initializer, then we need to check if the initializer expression matches the type annotation if(!initializerType->canAssignTo(declaredType)) { error(node, Errors::E_CANNOT_CONVERT_EXPRESSION_TYPE_2, initializerType->toString(), declaredType->toString()); return; } } else { node->setType(initializerType); } } //add implicitly constructor for Optional IdentifierPtr id = static_pointer_cast<Identifier>(node->getName()); SymbolScope* currentScope = symbolRegistry->getCurrentScope(); TypePtr declaredType = node->getType() ? node->getType() : lookupType(node->getDeclaredType()); SCOPED_SET(ctx->contextualType, declaredType); if(!declaredType && !node->getInitializer()) { error(node, Errors::E_TYPE_ANNOTATION_MISSING_IN_PATTERN); return; } SymbolPtr sym = currentScope->lookup(id->getIdentifier()); assert(sym != nullptr); SymbolPlaceHolderPtr placeholder = std::dynamic_pointer_cast<SymbolPlaceHolder>(sym); assert(placeholder != nullptr); if(declaredType) { placeholder->setType(declaredType); } ExpressionPtr initializer = node->getInitializer(); if(initializer) { placeholder->setFlags(SymbolFlagInitializing, true); ExpressionPtr initializer = transformExpression(declaredType, node->getInitializer()); node->setInitializer(initializer); TypePtr actualType = initializer->getType(); assert(actualType != nullptr); if(declaredType) { if(!Type::equals(actualType, declaredType) && !canConvertTo(initializer, declaredType)) { error(initializer, Errors::E_CANNOT_CONVERT_EXPRESSION_TYPE_2, actualType->toString(), declaredType->toString()); return; } } if(!declaredType) placeholder->setType(actualType); } assert(placeholder->getType() != nullptr); placeholder->setFlags(SymbolFlagInitializing, false); //optional type always considered initialized, compiler will make it has a default value nil TypePtr symbolType = sym->getType(); GlobalScope* global = symbolRegistry->getGlobalScope(); if(initializer || global->isOptional(symbolType) || global->isImplicitlyUnwrappedOptional(symbolType)) markInitialized(placeholder); if (initializer) placeholder->setFlags(SymbolFlagHasInitializer, true); if(node->isTemporary()) { placeholder->setFlags(SymbolFlagTemporary, true); markInitialized(placeholder); } if(!node->isTemporary()) { //check access control level DeclarationType decl = ctx->currentType ? DeclarationTypeProperty : DeclarationTypeVariable; declarationAnalyzer->verifyAccessLevel(node->getOwner(), placeholder->getType(), decl, ComponentTypeType); } if(ctx->currentType && ctx->currentType->getCategory() == Type::Protocol) { error(node, Errors::E_PROTOCOL_VAR_MUST_BE_COMPUTED_PROPERTY_1); } }