New Mojom Parser: Validate the use of '&' and '?'

The parser was not validating that after a user-defined type reference is resolved, that if the reference used a '&' or a '?' (or both) that the reference had resolved to a type for which this makes sense. This patch implements that.

BUG=#461
R=azani@chromium.org

Review URL: https://codereview.chromium.org/1515343002 .
diff --git a/mojom/mojom_parser/mojom/types.go b/mojom/mojom_parser/mojom/types.go
index 83cc4f7..f723b08 100644
--- a/mojom/mojom_parser/mojom/types.go
+++ b/mojom/mojom_parser/mojom/types.go
@@ -813,6 +813,21 @@
 	if ref.scope != nil && ref.scope.file != nil {
 		file = ref.scope.file
 	}
+
+	if ref.IsInterfaceRequest() && ref.resolvedType.Kind() != UserDefinedTypeKindInterface {
+		message := fmt.Sprintf("Invalid interface request specification: %s. %s is not an interface type.",
+			ref.TypeName(), ref.ResolvedType().FullyQualifiedName())
+		message = UserErrorMessage(file, ref.token, message)
+		return fmt.Errorf(message)
+	}
+
+	if ref.Nullable() && ref.resolvedType.Kind() == UserDefinedTypeKindEnum {
+		message := fmt.Sprintf("The type %s is invalid because %s is an enum type and these may not be made nullable.",
+			ref.TypeName(), ref.ResolvedType().FullyQualifiedName())
+		message = UserErrorMessage(file, ref.token, message)
+		return fmt.Errorf(message)
+	}
+
 	if ref.resolvedType.Kind() != UserDefinedTypeKindEnum {
 		// A type ref has resolved to a non-enum type. Make sure it is not
 		// being used as either a map key or a constant declaration. Also
diff --git a/mojom/mojom_parser/parser/resolution_test.go b/mojom/mojom_parser/parser/resolution_test.go
index 9e3857f..80f4d7b 100644
--- a/mojom/mojom_parser/parser/resolution_test.go
+++ b/mojom/mojom_parser/parser/resolution_test.go
@@ -827,6 +827,66 @@
 	}
 
 	////////////////////////////////////////////////////////////
+	// Group 3: Invalid use of interface request.
+	////////////////////////////////////////////////////////////
+
+	////////////////////////////////////////////////////////////
+	// Test Case: Make an interface request out of a struct
+	////////////////////////////////////////////////////////////
+	{
+		contents := `
+	struct Foo{
+	};
+
+    struct Bar{
+    	Foo& x;
+	};
+	`
+		test.addTestCase(contents, []string{
+			"Invalid interface request specification",
+			"Foo&. Foo is not an interface type"})
+	}
+
+	////////////////////////////////////////////////////////////
+	// Test Case: Make a nullable interface request out of a struct
+	////////////////////////////////////////////////////////////
+	{
+		contents := `
+	struct Foo{
+	};
+
+    struct Bar{
+    	Foo&? x;
+	};
+	`
+		test.addTestCase(contents, []string{
+			"Invalid interface request specification",
+			"Foo&?. Foo is not an interface type"})
+	}
+
+	////////////////////////////////////////////////////////////
+	// Group 4: Invalid use of nullable
+	////////////////////////////////////////////////////////////
+
+	////////////////////////////////////////////////////////////
+	// Test Case: Make nullable enum.
+	////////////////////////////////////////////////////////////
+	{
+		contents := `
+	enum Hats {
+		COWBOY,
+		TOP
+	};
+
+    struct Bar{
+    	Hats? my_hat;
+	};
+	`
+		test.addTestCase(contents, []string{
+			"The type Hats? is invalid because Hats is an enum type and these may not be made nullable."})
+	}
+
+	////////////////////////////////////////////////////////////
 	// Execute all of the test cases.
 	////////////////////////////////////////////////////////////
 	for i, c := range test.cases {