Skip to content

Dead Code/Declarations Due to Never #60338

Open
@RohitSaily

Description

@RohitSaily

Dart SDK version: 3.8.0-149.0.dev (dev) (Thu Feb 27 04:01:43 2025 -0800) on "macos_x64"

There are several ways to use Never to create dead code or declarations that are impossible to use, without getting any static warnings.

Examples

All the dead code or declarations discussed here are not currently recognized by static analysis.

The following type cast is dead code. The exit is performed but the casting of the result is dead code.

int i()=>
	exit(1) as int;

The following function can never run because it needs a Never instance as input.

void f<T extends Never>(T never)
{}

The following function can be run without issue because its type parameter is satisfied by Never.

void f<T extends Never>()
{}
void main()
{	f();
}

Static analysis can even be satisfied at the call site by using an expression which evaluates to Never as input. Since that expression evaluates to Never the subsequent evaluation of f is impossible, and that call is dead code.

import 'dart:io';
void f<T extends Never>(T never)
{}
void main()
{	f(exit(1));
}

Similarly I can define a class with an assignable Never field.

final class No
{	Never field;
	No(this.field);
}

This can never be instantiated, the entire declaration's instance members and constructors become dead declarations. Its static members would still be usable, as long as they don't require Never objects to be inputted. The Never object doesn't necessarily need to be declared as a stored field, the result is the same if the class can only be constructed via constructors which require Never input.

final class No
{	No(Never field);
}

It is possible for only constructors to be dead declarations and still have instance API be usable if there exists a way to construct without Never input.

final class Yes
{	Yes.no(Never field);//This is a dead declaration.
	Yes();//This is not, so the class can still be instantiated and any instance members can be used.
}

Similarly from #60251, impossible to use instance API can be declared.

extension on Never
{	int get impossible=>
		0;
}

In that issue, @FMorschel also pointed this out for extension types.

extension type No(Never no)
{}

Expectation

Any function which requires a Never object to be specified as input should be marked as a dead declaration/code. Any type declaring a Never object as a stored field or requiring Never as input in order to be instantiated should have all its instance methods and constructors marked as dead declarations. Furthermore, any type that extends or mixes in such code would have to do the same. In the case of implements it is possible to override the field as a getter and therefore does not necessarily render the type nonusable.

final class No
{	final Never field;
	No(this.field);//Can't instantiate!
}
final class Yes implements No
{	@override Never get field=>
		throw Error();
	Yes();//Can instantiate!
}

It can also be indicated that if the type is intended to only be implemented, it should be declared as an abstract interface class instead.

Related Issues and Discussions

Related to the currently open issues

Related to the recently closed issue

There's also the discussion which Never analysis issues spawned from dart-lang/language#4279

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2A bug or feature request we're likely to work onarea-devexpFor issues related to the analysis server, IDE support, linter, `dart fix`, and diagnostic messages.devexp-warningIssues with the analyzer's Warning codestype-enhancementA request for a change that isn't a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions