return
}
- // mayConvert reports whether the operands x and y may
- // possibly have matching types after converting one
- // untyped operand to the type of the other.
- // If mayConvert returns true, we try to convert the
- // operands to each other's types, and if that fails
- // we report a conversion failure.
- // If mayConvert returns false, we continue without an
- // attempt at conversion, and if the operand types are
- // not compatible, we report a type mismatch error.
- mayConvert := func(x, y *operand) bool {
- // If both operands are typed, there's no need for an implicit conversion.
- if isTyped(x.typ) && isTyped(y.typ) {
- return false
- }
- // An untyped operand may convert to its default type when paired with an empty interface
- // TODO(gri) This should only matter for comparisons (the only binary operation that is
- // valid with interfaces), but in that case the assignability check should take
- // care of the conversion. Verify and possibly eliminate this extra test.
- if isNonTypeParamInterface(x.typ) || isNonTypeParamInterface(y.typ) {
- return true
- }
- // A boolean type can only convert to another boolean type.
- if allBoolean(x.typ) != allBoolean(y.typ) {
- return false
- }
- // A string type can only convert to another string type.
- if allString(x.typ) != allString(y.typ) {
- return false
- }
- // Untyped nil can only convert to a type that has a nil.
- if x.isNil() {
- return hasNil(y.typ)
- }
- if y.isNil() {
- return hasNil(x.typ)
- }
- // An untyped operand cannot convert to a pointer.
- // TODO(gri) generalize to type parameters
- if isPointer(x.typ) || isPointer(y.typ) {
- return false
- }
- return true
- }
- if mayConvert(x, &y) {
- check.convertUntyped(x, y.typ)
- if x.mode == invalid {
- return
- }
- check.convertUntyped(&y, x.typ)
- if y.mode == invalid {
- x.mode = invalid
- return
- }
+ check.matchTypes(x, &y)
+ if x.mode == invalid {
+ return
}
if isComparison(op) {
// x.typ is unchanged
}
+// matchTypes attempts to convert any untyped types x and y such that they match.
+// If an error occurs, x.mode is set to invalid.
+func (check *Checker) matchTypes(x, y *operand) {
+ // mayConvert reports whether the operands x and y may
+ // possibly have matching types after converting one
+ // untyped operand to the type of the other.
+ // If mayConvert returns true, we try to convert the
+ // operands to each other's types, and if that fails
+ // we report a conversion failure.
+ // If mayConvert returns false, we continue without an
+ // attempt at conversion, and if the operand types are
+ // not compatible, we report a type mismatch error.
+ mayConvert := func(x, y *operand) bool {
+ // If both operands are typed, there's no need for an implicit conversion.
+ if isTyped(x.typ) && isTyped(y.typ) {
+ return false
+ }
+ // An untyped operand may convert to its default type when paired with an empty interface
+ // TODO(gri) This should only matter for comparisons (the only binary operation that is
+ // valid with interfaces), but in that case the assignability check should take
+ // care of the conversion. Verify and possibly eliminate this extra test.
+ if isNonTypeParamInterface(x.typ) || isNonTypeParamInterface(y.typ) {
+ return true
+ }
+ // A boolean type can only convert to another boolean type.
+ if allBoolean(x.typ) != allBoolean(y.typ) {
+ return false
+ }
+ // A string type can only convert to another string type.
+ if allString(x.typ) != allString(y.typ) {
+ return false
+ }
+ // Untyped nil can only convert to a type that has a nil.
+ if x.isNil() {
+ return hasNil(y.typ)
+ }
+ if y.isNil() {
+ return hasNil(x.typ)
+ }
+ // An untyped operand cannot convert to a pointer.
+ // TODO(gri) generalize to type parameters
+ if isPointer(x.typ) || isPointer(y.typ) {
+ return false
+ }
+ return true
+ }
+
+ if mayConvert(x, y) {
+ check.convertUntyped(x, y.typ)
+ if x.mode == invalid {
+ return
+ }
+ check.convertUntyped(y, x.typ)
+ if y.mode == invalid {
+ x.mode = invalid
+ return
+ }
+ }
+}
+
// exprKind describes the kind of an expression; the kind
// determines if an expression is valid in 'statement context'.
type exprKind int
return
}
- // mayConvert reports whether the operands x and y may
- // possibly have matching types after converting one
- // untyped operand to the type of the other.
- // If mayConvert returns true, we try to convert the
- // operands to each other's types, and if that fails
- // we report a conversion failure.
- // If mayConvert returns false, we continue without an
- // attempt at conversion, and if the operand types are
- // not compatible, we report a type mismatch error.
- mayConvert := func(x, y *operand) bool {
- // If both operands are typed, there's no need for an implicit conversion.
- if isTyped(x.typ) && isTyped(y.typ) {
- return false
- }
- // An untyped operand may convert to its default type when paired with an empty interface
- // TODO(gri) This should only matter for comparisons (the only binary operation that is
- // valid with interfaces), but in that case the assignability check should take
- // care of the conversion. Verify and possibly eliminate this extra test.
- if isNonTypeParamInterface(x.typ) || isNonTypeParamInterface(y.typ) {
- return true
- }
- // A boolean type can only convert to another boolean type.
- if allBoolean(x.typ) != allBoolean(y.typ) {
- return false
- }
- // A string type can only convert to another string type.
- if allString(x.typ) != allString(y.typ) {
- return false
- }
- // Untyped nil can only convert to a type that has a nil.
- if x.isNil() {
- return hasNil(y.typ)
- }
- if y.isNil() {
- return hasNil(x.typ)
- }
- // An untyped operand cannot convert to a pointer.
- // TODO(gri) generalize to type parameters
- if isPointer(x.typ) || isPointer(y.typ) {
- return false
- }
- return true
- }
- if mayConvert(x, &y) {
- check.convertUntyped(x, y.typ)
- if x.mode == invalid {
- return
- }
- check.convertUntyped(&y, x.typ)
- if y.mode == invalid {
- x.mode = invalid
- return
- }
+ check.matchTypes(x, &y)
+ if x.mode == invalid {
+ return
}
if isComparison(op) {
// x.typ is unchanged
}
+// matchTypes attempts to convert any untyped types x and y such that they match.
+// If an error occurs, x.mode is set to invalid.
+func (check *Checker) matchTypes(x, y *operand) {
+ // mayConvert reports whether the operands x and y may
+ // possibly have matching types after converting one
+ // untyped operand to the type of the other.
+ // If mayConvert returns true, we try to convert the
+ // operands to each other's types, and if that fails
+ // we report a conversion failure.
+ // If mayConvert returns false, we continue without an
+ // attempt at conversion, and if the operand types are
+ // not compatible, we report a type mismatch error.
+ mayConvert := func(x, y *operand) bool {
+ // If both operands are typed, there's no need for an implicit conversion.
+ if isTyped(x.typ) && isTyped(y.typ) {
+ return false
+ }
+ // An untyped operand may convert to its default type when paired with an empty interface
+ // TODO(gri) This should only matter for comparisons (the only binary operation that is
+ // valid with interfaces), but in that case the assignability check should take
+ // care of the conversion. Verify and possibly eliminate this extra test.
+ if isNonTypeParamInterface(x.typ) || isNonTypeParamInterface(y.typ) {
+ return true
+ }
+ // A boolean type can only convert to another boolean type.
+ if allBoolean(x.typ) != allBoolean(y.typ) {
+ return false
+ }
+ // A string type can only convert to another string type.
+ if allString(x.typ) != allString(y.typ) {
+ return false
+ }
+ // Untyped nil can only convert to a type that has a nil.
+ if x.isNil() {
+ return hasNil(y.typ)
+ }
+ if y.isNil() {
+ return hasNil(x.typ)
+ }
+ // An untyped operand cannot convert to a pointer.
+ // TODO(gri) generalize to type parameters
+ if isPointer(x.typ) || isPointer(y.typ) {
+ return false
+ }
+ return true
+ }
+
+ if mayConvert(x, y) {
+ check.convertUntyped(x, y.typ)
+ if x.mode == invalid {
+ return
+ }
+ check.convertUntyped(y, x.typ)
+ if y.mode == invalid {
+ x.mode = invalid
+ return
+ }
+ }
+}
+
// exprKind describes the kind of an expression; the kind
// determines if an expression is valid in 'statement context'.
type exprKind int