// checkAndComputeOperator handles specialized logic for operator members. func (mb *MemberDecorator) checkAndComputeOperator(memberNode compilergraph.ModifiableGraphNode, name string) { name = strings.ToLower(name) // Verify that the operator matches a known operator. definition, ok := mb.tdg.operators[name] if !ok { mb.tdg.decorateWithError(memberNode, "Unknown operator '%s' defined on type '%s'", name, mb.parent().Name()) return } // Some operators are static and some are assignable. mb.static = definition.IsStatic mb.readonly = !definition.IsAssignable // Ensure that the declared return type is equal to that expected. declaredReturnType := mb.memberType.Generics()[0] containingType := mb.tdg.NewInstanceTypeReference(mb.parent().AsType()) expectedReturnType := definition.ExpectedReturnType(containingType) if !mb.skipOperatorChecking { if !expectedReturnType.IsAny() && !declaredReturnType.IsAny() && declaredReturnType != expectedReturnType { mb.tdg.decorateWithError(memberNode, "Operator '%s' defined on type '%s' expects a return type of '%v'; found %v", name, mb.parent().Name(), expectedReturnType, declaredReturnType) return } } // Decorate the operator with its return type. var actualReturnType = expectedReturnType if expectedReturnType.IsAny() { actualReturnType = declaredReturnType } mb.CreateReturnable(mb.sourceNode, actualReturnType) // Ensure we have the expected number of parameters. parametersExpected := definition.Parameters if !mb.skipOperatorChecking { if mb.memberType.ParameterCount() != len(parametersExpected) { mb.tdg.decorateWithError(memberNode, "Operator '%s' defined on type '%s' expects %v parameters; found %v", name, mb.parent().Name(), len(parametersExpected), mb.memberType.ParameterCount()) return } } var memberType = mb.tdg.NewTypeReference(mb.tdg.FunctionType(), actualReturnType) // Ensure the parameters expected on the operator match those specified. parameterTypes := mb.memberType.Parameters() for index, parameterType := range parameterTypes { if !mb.skipOperatorChecking { expectedType := parametersExpected[index].ExpectedType(containingType) if !expectedType.IsAny() && expectedType != parameterType { mb.tdg.decorateWithError(memberNode, "Parameter '%s' (#%v) for operator '%s' defined on type '%s' expects type %v; found %v", parametersExpected[index].Name, index, name, mb.parent().Name(), expectedType, parameterType) } } memberType = memberType.WithParameter(parameterType) } // Decorate the member with its type. memberNode.DecorateWithTagged(NodePredicateMemberType, memberType) // Decorate the member with its signature. if definition.IsStatic { mb.decorateWithSig(mb.tdg.AnyTypeReference()) } else { mb.decorateWithSig(memberType) } }