// 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() }