Переглянути джерело

[diagnostics] report unbound monomorphs

Simon Krajewski 3 роки тому
батько
коміт
94e1af2796

+ 5 - 0
src-json/warning.json

@@ -102,6 +102,11 @@
 		"name": "WConstructorInliningCancelled",
 		"doc": "Constructor call could not be inlined because a field is uninitialized",
 		"parent": "WTyper"
+	},
+	{
+		"name": "WUnboundMonomorph",
+		"doc": "At least a part of a publicly visible type is incomplete after typing",
+		"parent": "WTyper"
 	}
 
 ]

+ 19 - 6
src/context/display/diagnostics.ml

@@ -93,20 +93,34 @@ let check_other_things com e =
 	in
 	loop true e
 
-let prepare_field dctx com cf = match cf.cf_expr with
+let check_unbound_monos com options t p =
+	let rec has_unbound_mono t = match t with
+		| TMono m when m.tm_type = None -> true
+		| _ -> check_type has_unbound_mono t
+	in
+	if has_unbound_mono t then begin
+		com.warning WUnboundMonomorph [] ("Unbound monomorph in " ^ (s_type (print_context()) t)) p
+	end
+
+let prepare_field dctx com options cf =
+	let options = options @ Warning.from_meta cf.cf_meta in
+	check_unbound_monos com options cf.cf_type cf.cf_name_pos;
+	begin match cf.cf_expr with
 	| None -> ()
 	| Some e ->
 		find_unused_variables dctx e;
 		check_other_things com e;
 		DeprecationCheck.run_on_expr ~force:true com e
+	end
 
 let collect_diagnostics dctx com =
 	let open CompilationCache in
 	List.iter (function
 		| TClassDecl c when DiagnosticsPrinter.is_diagnostics_file com (com.file_keys#get c.cl_pos.pfile) ->
-			List.iter (prepare_field dctx com) c.cl_ordered_fields;
-			List.iter (prepare_field dctx com) c.cl_ordered_statics;
-			(match c.cl_constructor with None -> () | Some cf -> prepare_field dctx com cf);
+			let options = Warning.from_meta c.cl_meta in
+			List.iter (prepare_field dctx com options) c.cl_ordered_fields;
+			List.iter (prepare_field dctx com options) c.cl_ordered_statics;
+			(match c.cl_constructor with None -> () | Some cf -> prepare_field dctx com options cf);
 		| _ ->
 			()
 	) com.types;
@@ -187,5 +201,4 @@ let print com =
 	Json.string_of_json (DiagnosticsPrinter.json_of_diagnostics com dctx)
 
 let run com =
-	let dctx = prepare com in
-	dctx
+	prepare com

+ 20 - 0
src/core/tFunctions.ml

@@ -322,6 +322,26 @@ let iter loop t =
 	| TDynamic t2 ->
 		if t != t2 then	loop t2
 
+let check_type predicate t =
+	match t with
+	| TMono r ->
+		begin match r.tm_type with
+		| Some t ->
+			predicate t
+		| None ->
+			false
+		end
+	| TInst(_,tl) | TEnum(_,tl) | TType(_,tl) | TAbstract(_,tl) ->
+		List.exists predicate tl
+	| TFun(args,ret) ->
+		List.exists (fun (_,_,t) -> predicate t) args || predicate ret
+	| TAnon an ->
+		PMap.fold (fun  cf b -> b || predicate cf.cf_type) an.a_fields false
+	| TLazy f ->
+		predicate (lazy_type f)
+	| TDynamic t2 ->
+		if t2 != t then predicate t2 else false
+
 let duplicate t =
 	let monos = ref [] in
 	let rec loop t =

+ 3 - 1
std/StringTools.hx

@@ -211,7 +211,7 @@ class StringTools {
 	public static inline function contains(s:String, value:String):Bool {
 		#if (js && js_es >= 6)
 		return (cast s).includes(value);
-		#else 
+		#else
 		return s.indexOf(value) != -1;
 		#end
 	}
@@ -622,7 +622,9 @@ class StringTools {
 	#end
 
 	#if neko
+	@:haxe.warning("-WUnboundMonomorph")
 	private static var _urlEncode = neko.Lib.load("std", "url_encode", 1);
+	@:haxe.warning("-WUnboundMonomorph")
 	private static var _urlDecode = neko.Lib.load("std", "url_decode", 1);
 	#end
 

+ 1 - 0
std/haxe/io/FPHelper.hx

@@ -26,6 +26,7 @@ package haxe.io;
 	Helper that converts between floating point and binary representation.
 	Always works in low-endian encoding.
 **/
+@:haxe.warning("-WUnboundMonomorph")
 class FPHelper {
 	#if neko_v21
 	// stored in helper

+ 2 - 0
std/haxe/io/Input.hx

@@ -312,7 +312,9 @@ class Input {
 	}
 
 	#if neko
+	@:haxe.warning("-WUnboundMonomorph")
 	static var _float_of_bytes = neko.Lib.load("std", "float_of_bytes", 2);
+	@:haxe.warning("-WUnboundMonomorph")
 	static var _double_of_bytes = neko.Lib.load("std", "double_of_bytes", 2);
 
 	static function __init__()

+ 1 - 0
std/neko/Boot.hx

@@ -24,6 +24,7 @@ package neko;
 
 @:dox(hide)
 @:keep
+@:haxe.warning("-WUnboundMonomorph")
 class Boot {
 	private static function __tmp_str() {
 		return untyped "<...>".__s;

+ 1 - 0
std/neko/Lib.hx

@@ -27,6 +27,7 @@ package neko;
 	for the Neko target, such as conversion from Haxe types to native types
 	and vice-versa.
 **/
+@:haxe.warning("-WUnboundMonomorph")
 class Lib {
 	/**
 		Load and return a Neko primitive from a NDLL library.

+ 1 - 0
std/neko/_std/Date.hx

@@ -22,6 +22,7 @@
 
 import neko.Lib;
 
+@:haxe.warning("-WUnboundMonomorph")
 @:coreApi final class Date {
 	private var __t:Dynamic;
 

+ 1 - 0
std/neko/_std/EReg.hx

@@ -19,6 +19,7 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
+@:haxe.warning("-WUnboundMonomorph")
 @:coreApi final class EReg {
 	var r:Dynamic;
 	var last:String;

+ 1 - 0
std/neko/_std/Math.hx

@@ -24,6 +24,7 @@ import neko.Lib;
 
 @:native("Math")
 @:keep
+@:haxe.warning("-WUnboundMonomorph")
 private class MathImpl {
 	static var __rnd:Dynamic;
 	static var _rand_float = Lib.load("std", "random_float", 1);

+ 1 - 0
std/neko/_std/Reflect.hx

@@ -132,5 +132,6 @@
 		});
 	}
 
+	@:haxe.warning("-WUnboundMonomorph")
 	static var same_closure = try neko.Lib.load("std", "same_closure", 2) catch (e:Dynamic) function(f1, f2) return f1 == f2;
 }

+ 1 - 0
std/neko/_std/Sys.hx

@@ -21,6 +21,7 @@
  */
 import haxe.SysTools;
 
+@:haxe.warning("-WUnboundMonomorph")
 @:coreApi class Sys {
 
 	public static function print( v : Dynamic ) : Void {

+ 1 - 0
std/neko/_std/sys/FileSystem.hx

@@ -29,6 +29,7 @@ private enum FileKind {
 }
 
 @:coreApi
+@:haxe.warning("-WUnboundMonomorph")
 class FileSystem {
 	public static function exists(path:String):Bool {
 		return sys_exists(untyped (makeCompatiblePath(path)).__s);

+ 1 - 0
std/neko/_std/sys/io/File.hx

@@ -24,6 +24,7 @@ package sys.io;
 
 enum FileHandle {}
 
+@:haxe.warning("-WUnboundMonomorph")
 @:coreApi class File {
 	public static function getContent(path:String):String {
 		return new String(file_contents(untyped path.__s));

+ 1 - 0
std/neko/_std/sys/io/FileInput.hx

@@ -22,6 +22,7 @@
 
 package sys.io;
 
+@:haxe.warning("-WUnboundMonomorph")
 @:coreApi class FileInput extends haxe.io.Input {
 	private var __f:File.FileHandle;
 

+ 1 - 0
std/neko/_std/sys/io/FileOutput.hx

@@ -22,6 +22,7 @@
 
 package sys.io;
 
+@:haxe.warning("-WUnboundMonomorph")
 @:coreApi class FileOutput extends haxe.io.Output {
 	private var __f:File.FileHandle;
 

+ 1 - 0
std/neko/_std/sys/thread/Tls.hx

@@ -23,6 +23,7 @@
 package sys.thread;
 
 @:coreApi
+@:haxe.warning("-WUnboundMonomorph")
 class Tls<T> {
 	var t:Dynamic;
 

+ 1 - 0
std/neko/vm/Loader.hx

@@ -44,6 +44,7 @@ abstract LoaderHandle {}
 	primitives can be loaded by this module or by rewrapping them at loading-time
 	with custom secured versions. Loaders are inherited in loaded submodules.
 **/
+@:haxe.warning("-WUnboundMonomorph")
 class Loader {
 	/**
 		The abstract handle.

+ 1 - 0
std/neko/vm/Module.hx

@@ -33,6 +33,7 @@ abstract ModuleHandle {}
 	A Neko Module represent a execution unit for the Neko Virtual Machine.
 	Each compiled `.n` bytecode file is a module once loaded by the NekoVM.
 **/
+@:haxe.warning("-WUnboundMonomorph")
 class Module {
 	/**
 		The abstract handle.