示例#1
0
// 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)
	}
}