Refine Dart 3 no-null output (#3723)

diff --git a/lib/src/solver/incompatibility.dart b/lib/src/solver/incompatibility.dart
index dbaf5bd..f471b05 100644
--- a/lib/src/solver/incompatibility.dart
+++ b/lib/src/solver/incompatibility.dart
@@ -121,13 +121,17 @@
       assert(terms.first.isPositive);
 
       var cause = this.cause as SdkCause;
-      var buffer = StringBuffer(
-          '${_terse(terms.first, details, allowEvery: true)} requires ');
-      if (!cause.sdk.isAvailable) {
-        buffer.write('the ${cause.sdk.name} SDK');
+      var buffer = StringBuffer(_terse(terms.first, details, allowEvery: true));
+      if (cause.noNullSafetyCause) {
+        buffer.write(' doesn\'t support null safety');
       } else {
-        if (cause.sdk.name != 'Dart') buffer.write('${cause.sdk.name} ');
-        buffer.write('SDK version ${cause.constraint}');
+        buffer.write(' requires ');
+        if (!cause.sdk.isAvailable) {
+          buffer.write('the ${cause.sdk.name} SDK');
+        } else {
+          if (cause.sdk.name != 'Dart') buffer.write('${cause.sdk.name} ');
+          buffer.write('SDK version ${cause.constraint}');
+        }
       }
       return buffer.toString();
     } else if (cause == IncompatibilityCause.noVersions) {
@@ -410,12 +414,16 @@
       buffer.write('but the latest version ($latest) is required');
     } else if (latter.cause is SdkCause) {
       var cause = latter.cause as SdkCause;
-      buffer.write('which requires ');
-      if (!cause.sdk.isAvailable) {
-        buffer.write('the ${cause.sdk.name} SDK');
+      if (cause.noNullSafetyCause) {
+        buffer.write('which doesn\'t support null safety');
       } else {
-        if (cause.sdk.name != 'Dart') buffer.write('${cause.sdk.name} ');
-        buffer.write('SDK version ${cause.constraint}');
+        buffer.write('which requires ');
+        if (!cause.sdk.isAvailable) {
+          buffer.write('the ${cause.sdk.name} SDK');
+        } else {
+          if (cause.sdk.name != 'Dart') buffer.write('${cause.sdk.name} ');
+          buffer.write('SDK version ${cause.constraint}');
+        }
       }
     } else if (latter.cause == IncompatibilityCause.noVersions) {
       buffer.write("which doesn't match any versions");
diff --git a/lib/src/solver/incompatibility_cause.dart b/lib/src/solver/incompatibility_cause.dart
index f414c01..c8f2db8 100644
--- a/lib/src/solver/incompatibility_cause.dart
+++ b/lib/src/solver/incompatibility_cause.dart
@@ -81,6 +81,11 @@
   /// The SDK with which the package was incompatible.
   final Sdk sdk;
 
+  bool get noNullSafetyCause =>
+      sdk.isDartSdk &&
+      !LanguageVersion.fromSdkConstraint(constraint).supportsNullSafety &&
+      sdk.version! >= Version(3, 0, 0).firstPreRelease;
+
   @override
   String? get notice {
     // If the SDK is not available, then we have an actionable [hint] printed
@@ -97,10 +102,10 @@
 
   @override
   String? get hint {
-    if (sdk.isDartSdk &&
-        !LanguageVersion.fromSdkConstraint(constraint).supportsNullSafety &&
-        sdk.version! >= Version(3, 0, 0).firstPreRelease) {
-      return 'The lower bound of "$constraint" does not enable null safety.';
+    if (noNullSafetyCause) {
+      return 'The lower bound of "sdk: \'$constraint\'" must be 2.12.0'
+          ' or higher to enable null safety.'
+          '\nFor details, see https://dart.dev/null-safety';
     }
     // If the SDK is available, then installing it won't help
     if (sdk.isAvailable) {
diff --git a/test/dart3_sdk_constraint_hack_test.dart b/test/dart3_sdk_constraint_hack_test.dart
index 25da55a..fe262d1 100644
--- a/test/dart3_sdk_constraint_hack_test.dart
+++ b/test/dart3_sdk_constraint_hack_test.dart
@@ -18,7 +18,7 @@
 
     await pubGet(
       error: contains(
-          'Because myapp requires SDK version >=2.11.0 <3.0.0, version solving failed'),
+          'Because myapp doesn\'t support null safety, version solving failed'),
       environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'},
     );
   });
@@ -47,7 +47,7 @@
 
     await pubGet(
       error: contains(
-          'Because myapp requires SDK version >=2.11.0 <2.999.0, version solving failed'),
+          'Because myapp doesn\'t support null safety, version solving failed'),
       environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'},
     );
   });
@@ -62,7 +62,7 @@
 
     await pubGet(
       error: contains(
-          'Because myapp requires SDK version >=2.11.0 <3.0.0-0.0, version solving failed'),
+          'Because myapp doesn\'t support null safety, version solving failed'),
       environment: {'_PUB_TEST_SDK_VERSION': '3.5.0'},
     );
   });
@@ -142,7 +142,8 @@
     });
     await pubGet(
       error: contains(
-        'The lower bound of ">=2.10.0 <3.0.0" does not enable null safety.',
+        'The lower bound of "sdk: \'>=2.10.0 <3.0.0\'" must be 2.12.0 or higher to enable null safety.'
+        '\nFor details, see https://dart.dev/null-safety',
       ),
     );
   });