}
// type-check package files
+ var firstHardErr error
conf := types.Config{
IgnoreFuncBodies: true,
FakeImportC: true,
- Importer: p,
- Sizes: p.sizes,
+ // continue type-checking after the first error
+ Error: func(err error) {
+ if firstHardErr == nil && !err.(types.Error).Soft {
+ firstHardErr = err
+ }
+ },
+ Importer: p,
+ Sizes: p.sizes,
}
pkg, err = conf.Check(bp.ImportPath, p.fset, files, nil)
if err != nil {
- // Type-checking stops after the first error (types.Config.Error is not set),
- // so the returned package is very likely incomplete. Don't return it since
- // we don't know its condition: It's very likely unsafe to use and it's also
- // not added to p.packages which may cause further problems (issue #20837).
- return nil, fmt.Errorf("type-checking package %q failed (%v)", bp.ImportPath, err)
+ // If there was a hard error it is possibly unsafe
+ // to use the package as it may not be fully populated.
+ // Do not return it (see also #20837, #20855).
+ if firstHardErr != nil {
+ pkg = nil
+ err = firstHardErr // give preference to first hard error over any soft error
+ }
+ return pkg, fmt.Errorf("type-checking package %q failed (%v)", bp.ImportPath, err)
+ }
+ if firstHardErr != nil {
+ // this can only happen if we have a bug in go/types
+ panic("package is not safe yet no error was returned")
}
p.packages[bp.ImportPath] = pkg
t.Errorf("got %v; want reimport error", err)
}
}
+
+func TestIssue20855(t *testing.T) {
+ if !testenv.HasSrc() {
+ t.Skip("no source code available")
+ }
+
+ pkg, err := importer.ImportFrom("go/internal/srcimporter/testdata/issue20855", ".", 0)
+ if err == nil || !strings.Contains(err.Error(), "missing function body") {
+ t.Fatalf("got unexpected or no error: %v", err)
+ }
+ if pkg == nil {
+ t.Error("got no package despite no hard errors")
+ }
+}