// ReturningResolvedTypeOf marks the scope as returning the *resolved* type of the given scope. func (sib *scopeInfoBuilder) ReturningResolvedTypeOf(scope *proto.ScopeInfo) *scopeInfoBuilder { resolvedValue := scope.GetResolvedType() settlesScope := true sib.info.ReturnedType = &resolvedValue sib.info.IsSettlingScope = &settlesScope return sib }
// scopeStructuralNewCloneExpression scopes a structural new expression for constructing a new instance // of a structural type by cloning and modifying an existing one. func (sb *scopeBuilder) scopeStructuralNewCloneExpression(node compilergraph.GraphNode, childScope *proto.ScopeInfo, context scopeContext) proto.ScopeInfo { resolvedTypeRef := childScope.ResolvedTypeRef(sb.sg.tdg) if !resolvedTypeRef.IsRefToStruct() { sb.decorateWithError(node, "Cannot clone and modify non-structural type %s", resolvedTypeRef) return newScope().Invalid().GetScope() } _, isValid := sb.scopeStructuralNewEntries(node, context) return newScope(). IsValid(isValid). Resolving(resolvedTypeRef). WithLabel(proto.ScopeLabel_STRUCTURAL_UPDATE_EXPR). GetScope() }
// getNamedScopeForScope returns namedScopeInfo for the given name, if it references a node by name. func (sb *scopeBuilder) getNamedScopeForScope(scope *proto.ScopeInfo) (namedScopeInfo, bool) { if scope.GetNamedReference() == nil { return namedScopeInfo{}, false } namedReference := scope.GetNamedReference() nodeId := compilergraph.GraphNodeId(namedReference.GetReferencedNode()) if namedReference.GetIsSRGNode() { referencedNode := sb.sg.srg.GetNamedScope(nodeId) return namedScopeInfo{referencedNode, nil, sb}, true } else { referencedNode := sb.sg.tdg.GetTypeOrMember(nodeId) return namedScopeInfo{srg.SRGNamedScope{}, referencedNode, sb}, true } }
// GetReferencedName returns the ReferencedName struct for the given scope, if it refers to a named scope. func (sg *ScopeGraph) GetReferencedName(scope proto.ScopeInfo) (ReferencedName, bool) { if scope.GetNamedReference() == nil { return ReferencedName{}, false } namedReference := scope.GetNamedReference() nodeId := compilergraph.GraphNodeId(namedReference.GetReferencedNode()) if namedReference.GetIsSRGNode() { referencedNode := sg.srg.GetNamedScope(nodeId) return ReferencedName{referencedNode, nil, sg}, true } else { referencedNode := sg.tdg.GetTypeOrMember(nodeId) return ReferencedName{srg.SRGNamedScope{}, referencedNode, sg}, true } }
// scopeStructuralNewTypeExpression scopes a structural new expression for constructing a new instance // of a structural or class type. func (sb *scopeBuilder) scopeStructuralNewTypeExpression(node compilergraph.GraphNode, childScope *proto.ScopeInfo, context scopeContext) proto.ScopeInfo { // Retrieve the static type. staticTypeRef := childScope.StaticTypeRef(sb.sg.tdg) // Ensure that the static type is a struct OR it is a class with an accessible 'new'. staticType := staticTypeRef.ReferredType() switch staticType.TypeKind() { case typegraph.ClassType: // Classes can only be constructed structurally if they are in the same module as this call. // Otherwise, an exported constructor must be used. module := compilercommon.InputSource(node.Get(parser.NodePredicateSource)) _, rerr := staticTypeRef.ResolveAccessibleMember("new", module, typegraph.MemberResolutionStatic) if rerr != nil { sb.decorateWithError(node, "Cannot structurally construct type %v, as it is imported from another module", staticTypeRef) return newScope().Invalid().Resolving(staticTypeRef).GetScope() } case typegraph.StructType: // Structs can be constructed by anyone, assuming that their members are all exported. // That check occurs below. break default: sb.decorateWithError(node, "Cannot structurally construct type %v", staticTypeRef) return newScope().Invalid().Resolving(staticTypeRef).GetScope() } encountered, isValid := sb.scopeStructuralNewEntries(node, context) if !isValid { return newScope().Invalid().Resolving(staticTypeRef).GetScope() } // Ensure that all required entries are present. for _, field := range staticType.RequiredFields() { if _, ok := encountered[field.Name()]; !ok { isValid = false sb.decorateWithError(node, "Non-nullable %v '%v' is required to construct type %v", field.Title(), field.Name(), staticTypeRef) } } return newScope().IsValid(isValid).Resolving(staticTypeRef).GetScope() }
// scopeDeclaredValue scopes a declared value (variable statement, variable member, type field). func (sb *scopeBuilder) scopeDeclaredValue(node compilergraph.GraphNode, title string, option requiresInitializerOption, exprPredicate compilergraph.Predicate, context scopeContext) proto.ScopeInfo { var exprScope *proto.ScopeInfo = nil exprNode, hasExpression := node.TryGetNode(exprPredicate) if hasExpression { // Scope the expression. exprScope = sb.getScope(exprNode, context) if !exprScope.GetIsValid() { return newScope().Invalid().GetScope() } } // Load the declared type, if any. declaredType, hasDeclaredType := sb.getDeclaredVariableType(node) if !hasDeclaredType { if exprScope == nil { panic("Somehow ended up with no declared type and no expr scope") } return newScope().Valid().AssignableResolvedTypeOf(exprScope).GetScope() } // Compare against the type of the expression. if hasExpression { exprType := exprScope.ResolvedTypeRef(sb.sg.tdg) if serr := exprType.CheckSubTypeOf(declaredType); serr != nil { sb.decorateWithError(node, "%s '%s' has declared type '%v': %v", title, node.Get(parser.NodeVariableStatementName), declaredType, serr) return newScope().Invalid().GetScope() } } else if option == requiresInitializer { // Make sure if the type is non-nullable that there is an expression. if !declaredType.IsNullable() { sb.decorateWithError(node, "%s '%s' must have explicit initializer as its type '%v' is non-nullable", title, node.Get(parser.NodeVariableStatementName), declaredType) return newScope().Invalid().Assignable(declaredType).GetScope() } } return newScope().Valid().Assignable(declaredType).GetScope() }
// AssignableResolvedTypeOf marks the scope as being assignable of the *resolved* type of the given scope. func (sib *scopeInfoBuilder) AssignableResolvedTypeOf(scope *proto.ScopeInfo) *scopeInfoBuilder { resolvedValue := scope.GetResolvedType() sib.info.AssignableType = &resolvedValue return sib }
// ResolvingTypeOf marks the scope as resolving the type of the given scope. func (sib *scopeInfoBuilder) ResolvingTypeOf(scope *proto.ScopeInfo) *scopeInfoBuilder { resolvedValue := scope.GetResolvedType() sib.info.ResolvedType = &resolvedValue return sib }