diff --git a/go/types/api.go b/go/types/api.go index 01d89281..025ccfef 100644 --- a/go/types/api.go +++ b/go/types/api.go @@ -79,6 +79,18 @@ type Importer func(map[string]*Package, string) (*Package, error) // A Config specifies the configuration for type checking. // The zero value for Config is a ready-to-use default configuration. type Config struct { + // If Strict is set, the type-checker enforces additional + // rules not specified by the Go 1 spec, but which will + // catch guaranteed run-time errors if the respective + // code is executed. In other words, programs passing in + // Strict mode are Go 1 compliant, but not all Go 1 programs + // will pass in Strict mode. The additional rules are: + // + // - A type assertion x.(T) where T is an interface type + // is invalid if any (statically known) method that exists + // for both x and T have different signatures. + Strict bool + // If IgnoreFuncBodies is set, function bodies are not // type-checked. IgnoreFuncBodies bool diff --git a/go/types/check_test.go b/go/types/check_test.go index cfea1ac9..e16e52e8 100644 --- a/go/types/check_test.go +++ b/go/types/check_test.go @@ -20,6 +20,9 @@ // _ = x /* ERROR "not declared" */ + 1 // } +// TODO(gri) Also collect strict mode errors of the form /* STRICT ... */ +// and test against strict mode. + package types_test import ( diff --git a/go/types/expr.go b/go/types/expr.go index 6cc572d9..22d5b804 100644 --- a/go/types/expr.go +++ b/go/types/expr.go @@ -1406,10 +1406,18 @@ Error: // typeAssertion checks that x.(T) is legal; xtyp must be the type of x. func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface, T Type) { + // no static check is required if T is an interface + // spec: "If T is an interface type, x.(T) asserts that the + // dynamic type of x implements the interface T." + if _, ok := T.Underlying().(*Interface); ok && !check.conf.Strict { + return + } + method, wrongType := MissingMethod(T, xtyp, false) if method == nil { return } + var msg string if wrongType { msg = "wrong type for method" diff --git a/go/types/testdata/expr3.src b/go/types/testdata/expr3.src index 3e710517..43825dd4 100644 --- a/go/types/testdata/expr3.src +++ b/go/types/testdata/expr3.src @@ -381,7 +381,7 @@ func type_asserts() { _ = t.(*T) _ = t /* ERROR "missing method m" */ .(T1) _ = t /* ERROR "wrong type for method m" */ .(T2) - _ = t /* ERROR "wrong type for method m" */ .(I2) + _ = t /* STRICT "wrong type for method m" */ .(I2) // only an error in strict mode (issue 8561) // e doesn't statically have an m, but may have one dynamically. _ = e.(I2) diff --git a/go/types/testdata/stmt0.src b/go/types/testdata/stmt0.src index 026d784e..a9e72996 100644 --- a/go/types/testdata/stmt0.src +++ b/go/types/testdata/stmt0.src @@ -558,7 +558,7 @@ func typeswitches() { case T: case T1 /* ERROR "missing method m" */ : case T2 /* ERROR "wrong type for method m" */ : - case I2 /* ERROR "wrong type for method m" */ : + case I2 /* STRICT "wrong type for method m" */ : // only an error in strict mode (issue 8561) } } @@ -596,7 +596,7 @@ func typeswitch2() { switch A(nil).(type) { case A: case B: - case C /* ERROR "cannot have dynamic type" */: + case C /* STRICT "cannot have dynamic type" */: // only an error in strict mode (issue 8561) } }