[cfe] Handle static gets and tearoffs in dot shorthands

Resolve static getters and tear-offs in dot shorthands.

Method and constructor invocations will come in a later CL. Also, looking to update the parser handling in a future CL, but we'll work incrementally.

Bug: https://github.com/dart-lang/sdk/issues/59758
Change-Id: I15c9eb7e531975ea19d496a03ac4b666fa15a04e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/411940
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
diff --git a/pkg/front_end/lib/src/kernel/body_builder.dart b/pkg/front_end/lib/src/kernel/body_builder.dart
index 661228f..323fff8 100644
--- a/pkg/front_end/lib/src/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/kernel/body_builder.dart
@@ -9976,23 +9976,29 @@
   }
 
   @override
-  // Coverage-ignore(suite): Not run.
   void handleDotShorthandContext(Token token) {
     debugEvent("DotShorthandContext");
     if (!libraryFeatures.dotShorthands.isEnabled) {
+      // Coverage-ignore-block(suite): Not run.
       addProblem(
           templateExperimentNotEnabledOffByDefault
               .withArguments(ExperimentalFlag.dotShorthands.name),
           token.offset,
           token.length);
+      return;
     }
+
+    // TODO(kallentu): Possibly could be ProblemBuilder? Testing needed.
+    assert(checkState(token, [ValueKinds.Expression]));
+    Expression value = pop() as Expression;
+    push(forest.createDotShorthandContext(token.charOffset, value));
   }
 
   @override
-  // Coverage-ignore(suite): Not run.
   void handleDotShorthandHead(Token token) {
     debugEvent("DotShorthandHead");
     if (!libraryFeatures.dotShorthands.isEnabled) {
+      // Coverage-ignore-block(suite): Not run.
       addProblem(
           templateExperimentNotEnabledOffByDefault
               .withArguments(ExperimentalFlag.dotShorthands.name),
@@ -10001,9 +10007,20 @@
 
       // Recovery, avoid crashing with an extra selector.
       pop();
+      return;
     }
 
-    // TODO(kallentu): Handle dot shorthands.
+    Object? selector = pop();
+    if (libraryFeatures.dotShorthands.isEnabled && selector is Selector) {
+      // TODO(kallentu): Remove this once we have more of the dot shorthands
+      // implementation complete.
+      pop(); // ParserGeneratorError
+
+      // TODO(kallentu): Handle invocations.
+
+      push(forest.createDotShorthandPropertyGet(
+          offsetForToken(token), selector.name));
+    }
   }
 }
 
diff --git a/pkg/front_end/lib/src/kernel/forest.dart b/pkg/front_end/lib/src/kernel/forest.dart
index 63e2020..da00ea7 100644
--- a/pkg/front_end/lib/src/kernel/forest.dart
+++ b/pkg/front_end/lib/src/kernel/forest.dart
@@ -928,13 +928,11 @@
       ..fileOffset = fileOffset;
   }
 
-  // Coverage-ignore(suite): Not run.
   DotShorthand createDotShorthandContext(
       int fileOffset, Expression innerExpression) {
     return new DotShorthand(innerExpression)..fileOffset = fileOffset;
   }
 
-  // Coverage-ignore(suite): Not run.
   DotShorthandPropertyGet createDotShorthandPropertyGet(
       int fileOffset, Name name) {
     return new DotShorthandPropertyGet(name)..fileOffset = fileOffset;
diff --git a/pkg/front_end/lib/src/kernel/hierarchy/members_builder.dart b/pkg/front_end/lib/src/kernel/hierarchy/members_builder.dart
index 31dc8bc..18a8363 100644
--- a/pkg/front_end/lib/src/kernel/hierarchy/members_builder.dart
+++ b/pkg/front_end/lib/src/kernel/hierarchy/members_builder.dart
@@ -202,6 +202,10 @@
     return getNodeFromClass(cls).getDispatchTarget(name, setter);
   }
 
+  Member? getStaticMember(Class cls, Name name, {bool setter = false}) {
+    return getNodeFromClass(cls).getStaticMember(name, setter)?.getMember(this);
+  }
+
   static ClassMembersBuilder build(
       ClassHierarchyBuilder hierarchyBuilder,
       List<ClassBuilder> classes,
diff --git a/pkg/front_end/lib/src/kernel/hierarchy/members_node.dart b/pkg/front_end/lib/src/kernel/hierarchy/members_node.dart
index 46b3e03..a240bff 100644
--- a/pkg/front_end/lib/src/kernel/hierarchy/members_node.dart
+++ b/pkg/front_end/lib/src/kernel/hierarchy/members_node.dart
@@ -1187,6 +1187,16 @@
     }
     return result;
   }
+
+  ClassMember? getStaticMember(Name name, bool isSetter) {
+    ClassMember? result = classMemberMap[name];
+    if (result == null) {
+      return null;
+    } else if (result.isStatic) {
+      return result;
+    }
+    return null;
+  }
 }
 
 // Coverage-ignore(suite): Not run.
diff --git a/pkg/front_end/lib/src/kernel/internal_ast.dart b/pkg/front_end/lib/src/kernel/internal_ast.dart
index 825bea8..e88c9d5 100644
--- a/pkg/front_end/lib/src/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/kernel/internal_ast.dart
@@ -3222,7 +3222,6 @@
       'ExtensionTypeRepresentationFieldInitializer(${toStringInternal()})';
 }
 
-// Coverage-ignore(suite): Not run.
 /// Internal expression for a dot shorthand.
 ///
 /// This node wraps around the [innerExpression] and indicates to the
@@ -3245,12 +3244,12 @@
   }
 
   @override
+  // Coverage-ignore(suite): Not run.
   void toTextInternal(AstPrinter printer) {
     printer.writeExpression(innerExpression);
   }
 }
 
-// Coverage-ignore(suite): Not run.
 /// Internal expression for a dot shorthand head with no arguments.
 /// (e.g. `.zero`).
 ///
@@ -3272,6 +3271,7 @@
   }
 
   @override
+  // Coverage-ignore(suite): Not run.
   void toTextInternal(AstPrinter printer) {
     printer.write('.');
     printer.writeName(name);
diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/type_inference/inference_visitor.dart
index a5d5249..ab40cdf 100644
--- a/pkg/front_end/lib/src/type_inference/inference_visitor.dart
+++ b/pkg/front_end/lib/src/type_inference/inference_visitor.dart
@@ -12104,7 +12104,6 @@
     return _unhandledStatement(node);
   }
 
-  // Coverage-ignore(suite): Not run.
   ExpressionInferenceResult visitDotShorthand(
       DotShorthand node, DartType typeContext) {
     DartType rewrittenType = analyzeDotShorthand(
@@ -12114,11 +12113,34 @@
     return new ExpressionInferenceResult(rewrittenType, rewrittenExpr);
   }
 
-  // Coverage-ignore(suite): Not run.
   ExpressionInferenceResult visitDotShorthandPropertyGet(
       DotShorthandPropertyGet node, DartType typeContext) {
-    // TODO(kallentu): Implementation needed for dot shorthands.
-    return _unhandledExpression(node, typeContext);
+    // Use the previously cached context type to determine the declaration
+    // member that we're trying to find.
+    DartType cachedContext = getDotShorthandContext().unwrapTypeSchemaView();
+    Member? member = findInterfaceMember(
+            cachedContext, node.name, node.fileOffset,
+            includeExtensionMethods: false,
+            isSetter: false,
+            isDotShorthand: true)
+        .member;
+
+    ExpressionInferenceResult expressionInferenceResult;
+    if (member == null) {
+      // TODO(kallentu): This is temporary. Build a problem with an error
+      // specific to not being able to find a member named [node.name].
+      throw 'Error: Cannot find dot shorthand member.';
+    } else if (member is Procedure && !member.isGetter) {
+      // Tearoff like `Object.new`;
+      expressionInferenceResult =
+          inferExpression(new StaticTearOff(member), cachedContext);
+    } else {
+      expressionInferenceResult =
+          inferExpression(new StaticGet(member), cachedContext);
+    }
+
+    flowAnalysis.forwardExpression(expressionInferenceResult.expression, node);
+    return expressionInferenceResult;
   }
 }
 
diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
index 2da0858..200357e 100644
--- a/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
+++ b/pkg/front_end/lib/src/type_inference/inference_visitor_base.dart
@@ -1181,7 +1181,8 @@
       DartType receiverType, Name name, int fileOffset,
       {required bool isSetter,
       bool instrumented = true,
-      bool includeExtensionMethods = false}) {
+      bool includeExtensionMethods = false,
+      bool isDotShorthand = false}) {
     assert(isKnown(receiverType));
 
     DartType receiverBound = receiverType.nonTypeParameterBound;
@@ -1200,6 +1201,7 @@
             classNode: classNode,
             receiverBound: receiverBound,
             hasNonObjectMemberAccess: hasNonObjectMemberAccess,
+            isDotShorthand: isDotShorthand,
             isSetter: isSetter,
             fileOffset: fileOffset);
 
@@ -3732,6 +3734,12 @@
     return TypeInferenceEngine.resolveInferenceNode(member, hierarchyBuilder);
   }
 
+  Member? _getStaticMember(Class class_, Name name, bool setter) {
+    Member? member =
+        engine.membersBuilder.getStaticMember(class_, name, setter: setter);
+    return TypeInferenceEngine.resolveInferenceNode(member, hierarchyBuilder);
+  }
+
   ClassMember? _getExtensionTypeMember(
       ExtensionTypeDeclaration extensionTypeDeclaration,
       Name name,
@@ -4617,6 +4625,7 @@
   final DartType receiverBound;
   final Class classNode;
   final bool hasNonObjectMemberAccess;
+  final bool isDotShorthand;
   final bool isSetter;
   final int fileOffset;
 
@@ -4626,6 +4635,7 @@
       required this.receiverBound,
       required this.classNode,
       required this.hasNonObjectMemberAccess,
+      required this.isDotShorthand,
       required this.isSetter,
       required this.fileOffset});
 
@@ -4717,8 +4727,9 @@
     }
 
     ObjectAccessTarget? target;
-    Member? interfaceMember =
-        visitor._getInterfaceMember(classNode, name, isSetter);
+    Member? interfaceMember = isDotShorthand
+        ? visitor._getStaticMember(classNode, name, isSetter)
+        : visitor._getInterfaceMember(classNode, name, isSetter);
     if (interfaceMember != null) {
       target = new ObjectAccessTarget.interfaceMember(
           receiverType, interfaceMember,
diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart
index 49848ae..3926175 100644
--- a/pkg/front_end/test/coverage_suite_expected.dart
+++ b/pkg/front_end/test/coverage_suite_expected.dart
@@ -590,7 +590,7 @@
   ),
   // 100.0%.
   "package:front_end/src/kernel/body_builder.dart": (
-    hitCount: 7188,
+    hitCount: 7216,
     missCount: 0,
   ),
   // 100.0%.
@@ -660,7 +660,7 @@
   ),
   // 100.0%.
   "package:front_end/src/kernel/forest.dart": (
-    hitCount: 396,
+    hitCount: 402,
     missCount: 0,
   ),
   // 100.0%.
@@ -695,12 +695,12 @@
   ),
   // 100.0%.
   "package:front_end/src/kernel/hierarchy/members_builder.dart": (
-    hitCount: 129,
+    hitCount: 133,
     missCount: 0,
   ),
   // 100.0%.
   "package:front_end/src/kernel/hierarchy/members_node.dart": (
-    hitCount: 1106,
+    hitCount: 1110,
     missCount: 0,
   ),
   // 100.0%.
@@ -720,7 +720,7 @@
   ),
   // 100.0%.
   "package:front_end/src/kernel/internal_ast.dart": (
-    hitCount: 565,
+    hitCount: 571,
     missCount: 0,
   ),
   // 100.0%.
@@ -976,12 +976,12 @@
   ),
   // 100.0%.
   "package:front_end/src/type_inference/inference_visitor.dart": (
-    hitCount: 8260,
+    hitCount: 8283,
     missCount: 0,
   ),
   // 100.0%.
   "package:front_end/src/type_inference/inference_visitor_base.dart": (
-    hitCount: 2442,
+    hitCount: 2451,
     missCount: 0,
   ),
   // 100.0%.
diff --git a/pkg/front_end/testcases/dot_shorthands/folder.options b/pkg/front_end/testcases/dot_shorthands/folder.options
new file mode 100644
index 0000000..88c4c4e
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/folder.options
@@ -0,0 +1 @@
+--enable-experiment=dot-shorthands
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_class.dart b/pkg/front_end/testcases/dot_shorthands/simple_class.dart
new file mode 100644
index 0000000..c568cf0
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_class.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Color {
+  final int x;
+  static Color get red => Color(1);
+  Color(this.x);
+}
+
+void main() {
+  Color c = .red;
+}
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_class.dart.strong.expect b/pkg/front_end/testcases/dot_shorthands/simple_class.dart.strong.expect
new file mode 100644
index 0000000..a02b6ea
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_class.dart.strong.expect
@@ -0,0 +1,23 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/dot_shorthands/simple_class.dart:12:13: Error: Expected an identifier, but got '.'.
+// Try inserting an identifier before '.'.
+//   Color c = .red;
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Color extends core::Object {
+  final field core::int x;
+  constructor •(core::int x) → self::Color
+    : self::Color::x = x, super core::Object::•()
+    ;
+  static get red() → self::Color
+    return new self::Color::•(1);
+}
+static method main() → void {
+  self::Color c = self::Color::red;
+}
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_class.dart.strong.modular.expect b/pkg/front_end/testcases/dot_shorthands/simple_class.dart.strong.modular.expect
new file mode 100644
index 0000000..a02b6ea
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_class.dart.strong.modular.expect
@@ -0,0 +1,23 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/dot_shorthands/simple_class.dart:12:13: Error: Expected an identifier, but got '.'.
+// Try inserting an identifier before '.'.
+//   Color c = .red;
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Color extends core::Object {
+  final field core::int x;
+  constructor •(core::int x) → self::Color
+    : self::Color::x = x, super core::Object::•()
+    ;
+  static get red() → self::Color
+    return new self::Color::•(1);
+}
+static method main() → void {
+  self::Color c = self::Color::red;
+}
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_class.dart.strong.outline.expect b/pkg/front_end/testcases/dot_shorthands/simple_class.dart.strong.outline.expect
new file mode 100644
index 0000000..9d722eb
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_class.dart.strong.outline.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Color extends core::Object {
+  final field core::int x;
+  constructor •(core::int x) → self::Color
+    ;
+  static get red() → self::Color
+    ;
+}
+static method main() → void
+  ;
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_class.dart.strong.transformed.expect b/pkg/front_end/testcases/dot_shorthands/simple_class.dart.strong.transformed.expect
new file mode 100644
index 0000000..a02b6ea
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_class.dart.strong.transformed.expect
@@ -0,0 +1,23 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/dot_shorthands/simple_class.dart:12:13: Error: Expected an identifier, but got '.'.
+// Try inserting an identifier before '.'.
+//   Color c = .red;
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Color extends core::Object {
+  final field core::int x;
+  constructor •(core::int x) → self::Color
+    : self::Color::x = x, super core::Object::•()
+    ;
+  static get red() → self::Color
+    return new self::Color::•(1);
+}
+static method main() → void {
+  self::Color c = self::Color::red;
+}
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_class.dart.textual_outline.expect b/pkg/front_end/testcases/dot_shorthands/simple_class.dart.textual_outline.expect
new file mode 100644
index 0000000..c010157
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_class.dart.textual_outline.expect
@@ -0,0 +1,7 @@
+class Color {
+  final int x;
+  static Color get red => Color(1);
+  Color(this.x);
+}
+
+void main() {}
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_class.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dot_shorthands/simple_class.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..5e453b4
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_class.dart.textual_outline_modelled.expect
@@ -0,0 +1,7 @@
+class Color {
+  Color(this.x);
+  final int x;
+  static Color get red => Color(1);
+}
+
+void main() {}
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_enum.dart b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart
new file mode 100644
index 0000000..03dad1d
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+enum Color { red, blue, green }
+
+void main() {
+  Color c = .red;
+}
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.strong.expect b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.strong.expect
new file mode 100644
index 0000000..072b755
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.strong.expect
@@ -0,0 +1,46 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/dot_shorthands/simple_enum.dart:8:13: Error: Expected an identifier, but got '.'.
+// Try inserting an identifier before '.'.
+//   Color c = .red;
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Color extends core::_Enum /*isEnum*/  {
+  enum-element static const field self::Color red = #C3;
+  enum-element static const field self::Color blue = #C6;
+  enum-element static const field self::Color green = #C9;
+  static const field core::List<self::Color> values = #C10;
+  const synthetic constructor •(core::int #index, core::String #name) → self::Color
+    : super core::_Enum::•(#index, #name)
+    ;
+  method _enumToString() → core::String
+    return "Color.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → void {
+  self::Color c = #C3;
+}
+
+constants  {
+  #C1 = 0
+  #C2 = "red"
+  #C3 = self::Color {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "blue"
+  #C6 = self::Color {index:#C4, _name:#C5}
+  #C7 = 2
+  #C8 = "green"
+  #C9 = self::Color {index:#C7, _name:#C8}
+  #C10 = <self::Color>[#C3, #C6, #C9]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///simple_enum.dart:
+- Color. (from org-dartlang-testcase:///simple_enum.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.strong.modular.expect b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.strong.modular.expect
new file mode 100644
index 0000000..072b755
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.strong.modular.expect
@@ -0,0 +1,46 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/dot_shorthands/simple_enum.dart:8:13: Error: Expected an identifier, but got '.'.
+// Try inserting an identifier before '.'.
+//   Color c = .red;
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Color extends core::_Enum /*isEnum*/  {
+  enum-element static const field self::Color red = #C3;
+  enum-element static const field self::Color blue = #C6;
+  enum-element static const field self::Color green = #C9;
+  static const field core::List<self::Color> values = #C10;
+  const synthetic constructor •(core::int #index, core::String #name) → self::Color
+    : super core::_Enum::•(#index, #name)
+    ;
+  method _enumToString() → core::String
+    return "Color.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → void {
+  self::Color c = #C3;
+}
+
+constants  {
+  #C1 = 0
+  #C2 = "red"
+  #C3 = self::Color {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "blue"
+  #C6 = self::Color {index:#C4, _name:#C5}
+  #C7 = 2
+  #C8 = "green"
+  #C9 = self::Color {index:#C7, _name:#C8}
+  #C10 = <self::Color>[#C3, #C6, #C9]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///simple_enum.dart:
+- Color. (from org-dartlang-testcase:///simple_enum.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.strong.outline.expect b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.strong.outline.expect
new file mode 100644
index 0000000..a370e0c
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.strong.outline.expect
@@ -0,0 +1,25 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Color extends core::_Enum /*isEnum*/  {
+  enum-element static const field self::Color red = const self::Color::•(0, "red");
+  enum-element static const field self::Color blue = const self::Color::•(1, "blue");
+  enum-element static const field self::Color green = const self::Color::•(2, "green");
+  static const field core::List<self::Color> values = const <self::Color>[self::Color::red, self::Color::blue, self::Color::green];
+  const synthetic constructor •(core::int #index, core::String #name) → self::Color
+    : super core::_Enum::•(#index, #name)
+    ;
+  method _enumToString() → core::String
+    return "Color.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → void
+  ;
+
+
+Extra constant evaluation status:
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///simple_enum.dart:5:14 -> InstanceConstant(const Color{_Enum.index: 0, _Enum._name: "red"})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///simple_enum.dart:5:19 -> InstanceConstant(const Color{_Enum.index: 1, _Enum._name: "blue"})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///simple_enum.dart:5:25 -> InstanceConstant(const Color{_Enum.index: 2, _Enum._name: "green"})
+Evaluated: ListLiteral @ org-dartlang-testcase:///simple_enum.dart:5:6 -> ListConstant(const <Color>[const Color{_Enum.index: 0, _Enum._name: "red"}, const Color{_Enum.index: 1, _Enum._name: "blue"}, const Color{_Enum.index: 2, _Enum._name: "green"}])
+Extra constant evaluation: evaluated: 9, effectively constant: 4
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.strong.transformed.expect b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.strong.transformed.expect
new file mode 100644
index 0000000..072b755
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.strong.transformed.expect
@@ -0,0 +1,46 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/dot_shorthands/simple_enum.dart:8:13: Error: Expected an identifier, but got '.'.
+// Try inserting an identifier before '.'.
+//   Color c = .red;
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Color extends core::_Enum /*isEnum*/  {
+  enum-element static const field self::Color red = #C3;
+  enum-element static const field self::Color blue = #C6;
+  enum-element static const field self::Color green = #C9;
+  static const field core::List<self::Color> values = #C10;
+  const synthetic constructor •(core::int #index, core::String #name) → self::Color
+    : super core::_Enum::•(#index, #name)
+    ;
+  method _enumToString() → core::String
+    return "Color.${this.{core::_Enum::_name}{core::String}}";
+}
+static method main() → void {
+  self::Color c = #C3;
+}
+
+constants  {
+  #C1 = 0
+  #C2 = "red"
+  #C3 = self::Color {index:#C1, _name:#C2}
+  #C4 = 1
+  #C5 = "blue"
+  #C6 = self::Color {index:#C4, _name:#C5}
+  #C7 = 2
+  #C8 = "green"
+  #C9 = self::Color {index:#C7, _name:#C8}
+  #C10 = <self::Color>[#C3, #C6, #C9]
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///simple_enum.dart:
+- Color. (from org-dartlang-testcase:///simple_enum.dart:5:6)
+- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.textual_outline.expect b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.textual_outline.expect
new file mode 100644
index 0000000..3931b1c
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+enum Color { red, blue, green }
+
+void main() {}
diff --git a/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..3931b1c
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/simple_enum.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+enum Color { red, blue, green }
+
+void main() {}
diff --git a/pkg/front_end/testcases/dot_shorthands/tearoff.dart b/pkg/front_end/testcases/dot_shorthands/tearoff.dart
new file mode 100644
index 0000000..e9986ca
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/tearoff.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void main() {
+  Object o = .hash;
+}
diff --git a/pkg/front_end/testcases/dot_shorthands/tearoff.dart.strong.expect b/pkg/front_end/testcases/dot_shorthands/tearoff.dart.strong.expect
new file mode 100644
index 0000000..0849169
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/tearoff.dart.strong.expect
@@ -0,0 +1,19 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/dot_shorthands/tearoff.dart:6:14: Error: Expected an identifier, but got '.'.
+// Try inserting an identifier before '.'.
+//   Object o = .hash;
+//              ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method main() → void {
+  core::Object o = #C1;
+}
+
+constants  {
+  #C1 = static-tearoff core::Object::hash
+}
diff --git a/pkg/front_end/testcases/dot_shorthands/tearoff.dart.strong.modular.expect b/pkg/front_end/testcases/dot_shorthands/tearoff.dart.strong.modular.expect
new file mode 100644
index 0000000..0849169
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/tearoff.dart.strong.modular.expect
@@ -0,0 +1,19 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/dot_shorthands/tearoff.dart:6:14: Error: Expected an identifier, but got '.'.
+// Try inserting an identifier before '.'.
+//   Object o = .hash;
+//              ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method main() → void {
+  core::Object o = #C1;
+}
+
+constants  {
+  #C1 = static-tearoff core::Object::hash
+}
diff --git a/pkg/front_end/testcases/dot_shorthands/tearoff.dart.strong.outline.expect b/pkg/front_end/testcases/dot_shorthands/tearoff.dart.strong.outline.expect
new file mode 100644
index 0000000..2982c48
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/tearoff.dart.strong.outline.expect
@@ -0,0 +1,5 @@
+library;
+import self as self;
+
+static method main() → void
+  ;
diff --git a/pkg/front_end/testcases/dot_shorthands/tearoff.dart.strong.transformed.expect b/pkg/front_end/testcases/dot_shorthands/tearoff.dart.strong.transformed.expect
new file mode 100644
index 0000000..0849169
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/tearoff.dart.strong.transformed.expect
@@ -0,0 +1,19 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/dot_shorthands/tearoff.dart:6:14: Error: Expected an identifier, but got '.'.
+// Try inserting an identifier before '.'.
+//   Object o = .hash;
+//              ^
+//
+import self as self;
+import "dart:core" as core;
+
+static method main() → void {
+  core::Object o = #C1;
+}
+
+constants  {
+  #C1 = static-tearoff core::Object::hash
+}
diff --git a/pkg/front_end/testcases/dot_shorthands/tearoff.dart.textual_outline.expect b/pkg/front_end/testcases/dot_shorthands/tearoff.dart.textual_outline.expect
new file mode 100644
index 0000000..ab73b3a
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/tearoff.dart.textual_outline.expect
@@ -0,0 +1 @@
+void main() {}
diff --git a/pkg/front_end/testcases/dot_shorthands/tearoff.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dot_shorthands/tearoff.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..ab73b3a
--- /dev/null
+++ b/pkg/front_end/testcases/dot_shorthands/tearoff.dart.textual_outline_modelled.expect
@@ -0,0 +1 @@
+void main() {}