proto: wrap pre-generated WKT libraries with go_proto_library (#2511)

Several of the well-known types have pre-generated code checked into
to both github.com/golang/protobuf (APIv1) and
google.golang.org/protobuf (APIv2). The APIv1 packages are just
wrappers for the APIv2 packages. We're using the APIv1 compiler, but
it won't generate these wrappers for us automatically. If we use it,
and a program also imports the APIv2 packages, we'll end up with a
registration conflict.

Instead, we'll use the pre-generated APIv1 code, but we'll wrap it up
in a go_proto_library so all the usual aspects and providers will
continue working.

Fixes #2501
diff --git a/proto/BUILD.bazel b/proto/BUILD.bazel
index 4d7a6d6..51d704d 100644
--- a/proto/BUILD.bazel
+++ b/proto/BUILD.bazel
@@ -1,12 +1,13 @@
-load("//proto:compiler.bzl", "go_proto_compiler")
-load("//proto/wkt:well_known_types.bzl", "GOGO_WELL_KNOWN_TYPE_REMAPS", "WELL_KNOWN_TYPE_RULES")
-
-PROTO_RUNTIME_DEPS = [
-    "@com_github_golang_protobuf//proto:go_default_library",
-    "@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
-    "@org_golang_google_protobuf//runtime/protoiface:go_default_library",
-    "@org_golang_google_protobuf//runtime/protoimpl:go_default_library",
-]
+load(
+    "//proto:compiler.bzl",
+    "go_proto_compiler",
+)
+load(
+    "//proto/wkt:well_known_types.bzl",
+    "GOGO_WELL_KNOWN_TYPE_REMAPS",
+    "PROTO_RUNTIME_DEPS",
+    "WELL_KNOWN_TYPE_RULES",
+)
 
 go_proto_compiler(
     name = "go_proto_bootstrap",
diff --git a/proto/compiler.bzl b/proto/compiler.bzl
index 14149d6..ae7c7bb 100644
--- a/proto/compiler.bzl
+++ b/proto/compiler.bzl
@@ -29,6 +29,19 @@
 GoProtoCompiler = provider()
 
 def go_proto_compile(go, compiler, protos, imports, importpath):
+    """Invokes protoc to generate Go sources for a given set of protos
+
+    Args:
+        go: the go object, returned by go_context.
+        compiler: a GoProtoCompiler provider.
+        protos: list of ProtoInfo providers for protos to compile.
+        imports: depset of strings mapping proto import paths to Go import paths.
+        importpath: the import path of the Go library being generated.
+
+    Returns:
+        A list of .go Files generated by the compiler.
+    """
+
     go_srcs = []
     outpath = None
     proto_paths = {}
diff --git a/proto/def.bzl b/proto/def.bzl
index 27b0235..0aa7120 100644
--- a/proto/def.bzl
+++ b/proto/def.bzl
@@ -13,8 +13,9 @@
 # limitations under the License.
 
 load(
-    "@io_bazel_rules_go//go:def.bzl",
+    "//go:def.bzl",
     "GoLibrary",
+    "GoSource",
     "go_context",
 )
 load(
@@ -74,10 +75,12 @@
 
 def _proto_library_to_source(go, attr, source, merge):
     if attr.compiler:
-        merge(source, attr.compiler)
-        return
-    for compiler in attr.compilers:
-        merge(source, compiler)
+        compilers = [attr.compiler]
+    else:
+        compilers = attr.compilers
+    for compiler in compilers:
+        if GoSource in compiler:
+            merge(source, compiler[GoSource])
 
 def _go_proto_library_impl(ctx):
     go = go_context(ctx)
diff --git a/proto/wkt/BUILD.bazel b/proto/wkt/BUILD.bazel
index baea35a..69605fb 100644
--- a/proto/wkt/BUILD.bazel
+++ b/proto/wkt/BUILD.bazel
@@ -1,6 +1,167 @@
-load("//proto/wkt:well_known_types.bzl", "gen_well_known_types")
+load(":well_known_types.bzl", "go_proto_wrapper")
+load("//proto:def.bzl", "go_proto_library")
 
-gen_well_known_types()
+# Several of the well-known types have pre-generated code checked into to both
+# github.com/golang/protobuf (APIv1) and google.golang.org/protobuf (APIv2).
+# The APIv1 packages are just wrappers for the APIv2 packages. We're using
+# the APIv1 compiler, but it won't generate these wrappers for us automatically.
+# If we use it, and a program also imports the APIv2 packages, we'll end up
+# with a registration conflict. Instead, we'll use the pre-generated APIv1
+# code, but we'll wrap it up in a go_proto_library.
+go_proto_wrapper(
+    name = "any_wrapper",
+    library = "@com_github_golang_protobuf//ptypes/any:go_default_library",
+    visibility = ["//visibility:private"],
+)
+
+go_proto_library(
+    name = "any_go_proto",
+    compilers = [":any_wrapper"],
+    importpath = "github.com/golang/protobuf/ptypes/any",
+    protos = ["@com_google_protobuf//:any_proto"],
+    visibility = ["//visibility:public"],
+)
+
+go_proto_wrapper(
+    name = "compiler_plugin_wrapper",
+    library = "@com_github_golang_protobuf//protoc-gen-go/plugin:go_default_library",
+    visibility = ["//visibility:private"],
+)
+
+go_proto_library(
+    name = "compiler_plugin_go_proto",
+    compilers = [":compiler_plugin_wrapper"],
+    importpath = "github.com/golang/protobuf/protoc-gen-go/plugin",
+    protos = ["@com_google_protobuf//:compiler_plugin_proto"],
+    visibility = ["//visibility:public"],
+)
+
+go_proto_wrapper(
+    name = "descriptor_wrapper",
+    library = "@com_github_golang_protobuf//protoc-gen-go/descriptor:go_default_library",
+    visibility = ["//visibility:private"],
+)
+
+go_proto_library(
+    name = "descriptor_go_proto",
+    compilers = [":descriptor_wrapper"],
+    importpath = "github.com/golang/protobuf/protoc-gen-go/descriptor",
+    protos = ["@com_google_protobuf//:descriptor_proto"],
+    visibility = ["//visibility:public"],
+)
+
+go_proto_wrapper(
+    name = "duration_wrapper",
+    library = "@com_github_golang_protobuf//ptypes/duration:go_default_library",
+    visibility = ["//visibility:private"],
+)
+
+go_proto_library(
+    name = "duration_go_proto",
+    compilers = [":duration_wrapper"],
+    importpath = "github.com/golang/protobuf/ptypes/duration",
+    protos = ["@com_google_protobuf//:duration_proto"],
+    visibility = ["//visibility:public"],
+)
+
+go_proto_wrapper(
+    name = "empty_wrapper",
+    library = "@com_github_golang_protobuf//ptypes/empty:go_default_library",
+    visibility = ["//visibility:private"],
+)
+
+go_proto_library(
+    name = "empty_go_proto",
+    compilers = [":empty_wrapper"],
+    importpath = "github.com/golang/protobuf/ptypes/empty",
+    protos = ["@com_google_protobuf//:empty_proto"],
+    visibility = ["//visibility:public"],
+)
+
+go_proto_wrapper(
+    name = "struct_wrapper",
+    library = "@com_github_golang_protobuf//ptypes/struct:go_default_library",
+    visibility = ["//visibility:private"],
+)
+
+go_proto_library(
+    name = "struct_go_proto",
+    compilers = [":struct_wrapper"],
+    importpath = "github.com/golang/protobuf/ptypes/struct",
+    protos = ["@com_google_protobuf//:struct_proto"],
+    visibility = ["//visibility:public"],
+)
+
+go_proto_wrapper(
+    name = "timestamp_wrapper",
+    library = "@com_github_golang_protobuf//ptypes/timestamp:go_default_library",
+    visibility = ["//visibility:private"],
+)
+
+go_proto_library(
+    name = "timestamp_go_proto",
+    compilers = [":timestamp_wrapper"],
+    importpath = "github.com/golang/protobuf/ptypes/timestamp",
+    protos = ["@com_google_protobuf//:timestamp_proto"],
+    visibility = ["//visibility:public"],
+)
+
+go_proto_wrapper(
+    name = "wrappers_wrapper",
+    library = "@com_github_golang_protobuf//ptypes/wrappers:go_default_library",
+    visibility = ["//visibility:private"],
+)
+
+go_proto_library(
+    name = "wrappers_go_proto",
+    compilers = [":wrappers_wrapper"],
+    importpath = "github.com/golang/protobuf/ptypes/wrappers",
+    protos = ["@com_google_protobuf//:wrappers_proto"],
+    visibility = ["//visibility:public"],
+)
+
+# Protos below this point don't have duplicate libraries, so we generate .pb.go
+# files at build time as usual. The only difference is we use
+# go_proto_bootstrap, which has an empty set of implicit dependencies.
+go_proto_library(
+    name = "api_go_proto",
+    compilers = ["//proto:go_proto_bootstrap"],
+    importpath = "google.golang.org/genproto/protobuf/api",
+    protos = ["@com_google_protobuf//:api_proto"],
+    visibility = ["//visibility:public"],
+    deps = [
+        ":source_context_go_proto",
+        ":type_go_proto",
+    ],
+)
+
+go_proto_library(
+    name = "field_mask_go_proto",
+    compilers = ["//proto:go_proto_bootstrap"],
+    importpath = "google.golang.org/genproto/protobuf/field_mask",
+    protos = ["@com_google_protobuf//:field_mask_proto"],
+    visibility = ["//visibility:public"],
+)
+
+go_proto_library(
+    name = "source_context_go_proto",
+    compilers = ["//proto:go_proto_bootstrap"],
+    importpath = "google.golang.org/genproto/protobuf/source_context",
+    protos = ["@com_google_protobuf//:source_context_proto"],
+    visibility = ["//visibility:public"],
+)
+
+go_proto_library(
+    name = "type_go_proto",
+    compilers = ["//proto:go_proto_bootstrap"],
+    importpath = "google.golang.org/genproto/protobuf/ptype",
+    protos = ["@com_google_protobuf//:type_proto"],
+    visibility = ["//visibility:public"],
+    deps = [
+        ":any_go_proto",
+        ":source_context_go_proto",
+    ],
+)
 
 filegroup(
     name = "all_rules",
diff --git a/proto/wkt/well_known_types.bzl b/proto/wkt/well_known_types.bzl
index 4ecdd0b..254ba6c 100644
--- a/proto/wkt/well_known_types.bzl
+++ b/proto/wkt/well_known_types.bzl
@@ -1,8 +1,11 @@
-load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+load("//go:def.bzl", "GoArchive", "GoLibrary", "GoSource")
+load("//proto:def.bzl", "go_proto_library")
+load("//proto:compiler.bzl", "GoProtoCompiler")
 
 _proto_library_suffix = "proto"
 _go_proto_library_suffix = "go_proto"
 
+# TODO: this should be private. Make sure nothing depends on it, then rename it.
 WELL_KNOWN_TYPE_PACKAGES = {
     "any": ("github.com/golang/protobuf/ptypes/any", []),
     "api": ("google.golang.org/genproto/protobuf/api", ["source_context", "type"]),
@@ -32,6 +35,13 @@
     for wkt in WELL_KNOWN_TYPE_PACKAGES.keys()
 }
 
+PROTO_RUNTIME_DEPS = [
+    "@com_github_golang_protobuf//proto:go_default_library",
+    "@org_golang_google_protobuf//reflect/protoreflect:go_default_library",
+    "@org_golang_google_protobuf//runtime/protoiface:go_default_library",
+    "@org_golang_google_protobuf//runtime/protoimpl:go_default_library",
+]
+
 def gen_well_known_types():
     for wkt, rule in WELL_KNOWN_TYPE_RULES.items():
         (go_package, deps) = WELL_KNOWN_TYPE_PACKAGES[wkt]
@@ -43,3 +53,31 @@
             visibility = ["//visibility:public"],
             deps = [WELL_KNOWN_TYPE_RULES[dep] for dep in deps],
         )
+
+def _go_proto_wrapper_compile(go, compiler, protos, imports, importpath):
+    return []
+
+def _go_proto_wrapper_impl(ctx):
+    return [
+        ctx.attr.library[GoLibrary],
+        ctx.attr.library[GoSource],
+        GoProtoCompiler(
+            deps = ctx.attr._deps,
+            compile = _go_proto_wrapper_compile,
+            valid_archive = True,
+        ),
+    ]
+
+go_proto_wrapper = rule(
+    implementation = _go_proto_wrapper_impl,
+    attrs = {
+        "library": attr.label(
+            mandatory = True,
+            providers = [GoLibrary, GoSource],
+        ),
+        "_deps": attr.label_list(
+            default = PROTO_RUNTIME_DEPS,
+            providers = [GoLibrary, GoSource, GoArchive],
+        ),
+    },
+)
diff --git a/tests/core/go_proto_library/BUILD.bazel b/tests/core/go_proto_library/BUILD.bazel
index 385d284..d55ba5d 100644
--- a/tests/core/go_proto_library/BUILD.bazel
+++ b/tests/core/go_proto_library/BUILD.bazel
@@ -276,3 +276,26 @@
     srcs = ["proto_package_test.go"],
     deps = [":no_go_package_go_proto"],
 )
+
+go_test(
+    name = "wkt_wrapper_test",
+    srcs = ["wkt_wrapper_test.go"],
+    deps = [
+        "//proto/wkt:any_go_proto",
+        "//proto/wkt:compiler_plugin_go_proto",
+        "//proto/wkt:descriptor_go_proto",
+        "//proto/wkt:duration_go_proto",
+        "//proto/wkt:empty_go_proto",
+        "//proto/wkt:struct_go_proto",
+        "//proto/wkt:timestamp_go_proto",
+        "//proto/wkt:wrappers_go_proto",
+        "@org_golang_google_protobuf//types/descriptorpb:go_default_library",
+        "@org_golang_google_protobuf//types/known/anypb:go_default_library",
+        "@org_golang_google_protobuf//types/known/durationpb:go_default_library",
+        "@org_golang_google_protobuf//types/known/emptypb:go_default_library",
+        "@org_golang_google_protobuf//types/known/structpb:go_default_library",
+        "@org_golang_google_protobuf//types/known/timestamppb:go_default_library",
+        "@org_golang_google_protobuf//types/known/wrapperspb:go_default_library",
+        "@org_golang_google_protobuf//types/pluginpb:go_default_library",
+    ],
+)
diff --git a/tests/core/go_proto_library/README.rst b/tests/core/go_proto_library/README.rst
index 31e2f10..4caa7cc 100644
--- a/tests/core/go_proto_library/README.rst
+++ b/tests/core/go_proto_library/README.rst
@@ -46,3 +46,10 @@
 Checks that `go_proto_library`_ generates files with a package name based on
 the proto package, not ``importpath`` when ``option go_package`` is not given.
 Verifies `#1596`_.
+
+wkt_wrapper_test
+----------------
+
+Checks that most of the well known types in ``//proto/wkt`` are wrappers
+for packages in ``@org_golang_google_protobuf``. The proto types should be
+type aliases.
diff --git a/tests/core/go_proto_library/wkt_wrapper_test.go b/tests/core/go_proto_library/wkt_wrapper_test.go
new file mode 100644
index 0000000..51ea2b6
--- /dev/null
+++ b/tests/core/go_proto_library/wkt_wrapper_test.go
@@ -0,0 +1,55 @@
+// Copyright 2020 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package wkt_wrapper_test
+
+import (
+	"testing"
+
+	descriptorpb1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
+	pluginpb1 "github.com/golang/protobuf/protoc-gen-go/plugin"
+	anypb1 "github.com/golang/protobuf/ptypes/any"
+	durationpb1 "github.com/golang/protobuf/ptypes/duration"
+	emptypb1 "github.com/golang/protobuf/ptypes/empty"
+	structpb1 "github.com/golang/protobuf/ptypes/struct"
+	timestamppb1 "github.com/golang/protobuf/ptypes/timestamp"
+	wrapperspb1 "github.com/golang/protobuf/ptypes/wrappers"
+	descriptorpb2 "google.golang.org/protobuf/types/descriptorpb"
+	anypb2 "google.golang.org/protobuf/types/known/anypb"
+	durationpb2 "google.golang.org/protobuf/types/known/durationpb"
+	emptypb2 "google.golang.org/protobuf/types/known/emptypb"
+	structpb2 "google.golang.org/protobuf/types/known/structpb"
+	timestamppb2 "google.golang.org/protobuf/types/known/timestamppb"
+	wrapperspb2 "google.golang.org/protobuf/types/known/wrapperspb"
+	pluginpb2 "google.golang.org/protobuf/types/pluginpb"
+)
+
+func Test(t *testing.T) {
+	var _ *anypb2.Any = (*anypb1.Any)(nil)
+	var _ *anypb1.Any = (*anypb2.Any)(nil)
+	var _ *pluginpb2.Version = (*pluginpb1.Version)(nil)
+	var _ *pluginpb1.Version = (*pluginpb2.Version)(nil)
+	var _ *descriptorpb2.DescriptorProto = (*descriptorpb1.DescriptorProto)(nil)
+	var _ *descriptorpb1.DescriptorProto = (*descriptorpb2.DescriptorProto)(nil)
+	var _ *durationpb2.Duration = (*durationpb1.Duration)(nil)
+	var _ *durationpb1.Duration = (*durationpb2.Duration)(nil)
+	var _ *emptypb2.Empty = (*emptypb1.Empty)(nil)
+	var _ *emptypb1.Empty = (*emptypb2.Empty)(nil)
+	var _ *structpb2.Struct = (*structpb1.Struct)(nil)
+	var _ *structpb1.Struct = (*structpb2.Struct)(nil)
+	var _ *timestamppb2.Timestamp = (*timestamppb1.Timestamp)(nil)
+	var _ *timestamppb1.Timestamp = (*timestamppb2.Timestamp)(nil)
+	var _ *wrapperspb2.BoolValue = (*wrapperspb1.BoolValue)(nil)
+	var _ *wrapperspb1.BoolValue = (*wrapperspb2.BoolValue)(nil)
+}