Basically one of the oldest bug of Nit.
The point of adaptive typing is that the static types of variables follows the static types of the assigned values, type tests and comparison to null.
This is a great feature of the language but was buggy because loops where not taken in account (old TODO), until the present PR.
The basic idea is just to track if a type adaptation occurs, if yes replay the whole typing phase.
The immediate drawback is that now typing require 2 passes most of the time, and sometime more.
This PR was a roller-coaster of emotions to develop since a lot a surprise issues were discovered.
* bug in flow that give me hours of despair.
* duplication of error messages; because multiple passes.
* premature warning/error messages; because some error conditions on types are detected at the first pass but a second pass find it is fine in fact... but too late the error message was printed.
* almost work at the first time (modulo the previous issues)
* only two bugs found in the whole code, quite impressive, and one of them is not a real bug but an autocast issue.
The issue about error duplication and premature errors is only workadounded (or fixme) in most places.
But proper solutions will be required in future PR.
close #647 and close #86, then reopen it again, then reclose it.
Pull-Request: #1257
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Theses services are implemented using the POSIX threads.
+You can also use the `is threaded` annotation on methods, which makes them run on their own thread.
+Methods with return value or self calls are not supported.
+
## Known limitations:
* Most services from the Nit library are not thread-safe. You must manage
import pthreads
-# the "is threaded" annotation makes this fun run on an other thread
+# the `is threaded` annotation makes this method run on an other thread
fun foo is threaded do
sys.nanosleep(1,0)
print "threaded"
end
+# Parameterized `threaded` method, same as foo, but with parameters
+fun bar(i : Int, s : String) is threaded do
+ sys.nanosleep(2, 0)
+ print i
+ print s
+end
+
foo
+bar(10, "parameterized and threaded")
print "main"
-sys.nanosleep(2,0)
+sys.nanosleep(5,0)
## Documentation in preview window
-You can display the documentation for the entity under the cursor with `:call Nitdoc()`.
-It will use the same metadata files as the omnifunc and the preview window.
+The command `:Nitdoc` searches the documentation for the word under the cursor.
+The results are displayed in the preview window in order of relevance.
+You can search for any word by passing it as an argument, as in `:Nitdoc modulo`.
+The Nitdoc command uses the same metadata files as the omnifunc.
You may want to map the function to a shortcut by adding the following code to `~/.vimrc`.
~~~
" Map displaying Nitdoc to Ctrl-D
-map <C-d> :call Nitdoc()<enter>
+map <C-d> :Nitdoc<enter>
~~~
## Search declarations and usages of the word under the cursor
" Get path to the best metadata file named `name`
"
" Returns an empty string if not found.
-fun NitMetadataFile(name)
+fun s:NitMetadataFile(name)
" Where are the generated metadata files?
if empty($NIT_VIM_DIR)
let metadata_dir = $HOME . '/.vim/nit'
let synopsis_matches = []
let doc_matches = []
- let path = NitMetadataFile(a:path)
+ let path = s:NitMetadataFile(a:path)
if empty(path)
return
endif
" Add?
if name == a:base
" Exact match
- call NitOmnifuncAddAMatch(a:matches, words, name)
+ call s:NitOmnifuncAddAMatch(a:matches, words, name)
elseif name =~? '^'.a:base
" Common-prefix match
- call NitOmnifuncAddAMatch(prefix_matches, words, name)
+ call s:NitOmnifuncAddAMatch(prefix_matches, words, name)
elseif name =~? a:base
" Substring match
- call NitOmnifuncAddAMatch(substring_matches, words, name)
+ call s:NitOmnifuncAddAMatch(substring_matches, words, name)
elseif get(words, 2, '') =~? a:base
" Match in the synopsis
- call NitOmnifuncAddAMatch(synopsis_matches, words, name)
+ call s:NitOmnifuncAddAMatch(synopsis_matches, words, name)
elseif get(words, 3, '') =~? a:base
" Match in the longer doc
- call NitOmnifuncAddAMatch(synopsis_matches, words, name)
+ call s:NitOmnifuncAddAMatch(doc_matches, words, name)
endif
endfor
endfun
" Internal function to search parse the information from a metadata line
-fun NitOmnifuncAddAMatch(matches, words, name)
+fun s:NitOmnifuncAddAMatch(matches, words, name)
let pretty = get(a:words, 1, '')
let synopsis = get(a:words, 2, '')
let desc = get(a:words, 3, '')
endfun
" Show doc for the entity under the cursor in the preview window
-fun Nitdoc()
- " Word under cursor
- let word = expand("<cword>")
+fun Nitdoc(...)
+ if a:0 == 0 || empty(a:1)
+ " Word under cursor
+ let word = expand("<cword>")
+ else
+ let word = join(a:000, ' ')
+ endif
" All possible docs (there may be more than one entity with the same name)
let docs = []
+ let prefix_matches = []
+ let substring_matches = []
+ let synopsis_matches = []
+ let doc_matches = []
" Search in all metadata files
for file in ['modules', 'classes', 'properties']
- let path = NitMetadataFile(file.'.txt')
+ let path = s:NitMetadataFile(file.'.txt')
if empty(path)
continue
endif
for line in readfile(path)
let words = split(line, '#====#', 1)
let name = get(words, 0, '')
- if name =~ '^' . word . '\>'
- " It fits our word, get long doc
- let desc = get(words,3,'')
- let desc = join(split(desc, '#nnnn#', 1), "\n")
- call add(docs, desc)
+ if name =~ '^'.word.'\>'
+ " Exact match
+ call s:NitdocAdd(docs, words)
+ elseif name =~? '^'.word
+ " Common-prefix match
+ call s:NitdocAdd(prefix_matches, words)
+ elseif name =~? word
+ " Substring match
+ call s:NitdocAdd(substring_matches, words)
+ elseif get(words, 2, '') =~? word
+ " Match in the synopsis
+ call s:NitdocAdd(synopsis_matches, words)
+ elseif get(words, 3, '') =~? word
+ " Match in the longer doc
+ call s:NitdocAdd(doc_matches, words)
endif
endfor
endfor
+ " Unite all results in prefered order
+ call extend(docs, sort(prefix_matches))
+ call extend(docs, sort(substring_matches))
+ call extend(docs, sort(synopsis_matches))
+ call extend(docs, sort(doc_matches))
+
" Found no doc, give up
if empty(docs) || !(join(docs, '') =~ '\w')
+ echo 'Nitdoc found nothing for "' . word . '"'
return
endif
silent put = ''
endif
endfor
+ execute 0
+ delete " the first empty line
" Set options
setlocal buftype=nofile
redraw!
endfun
+" Internal function to search parse the information from a metadata line
+fun s:NitdocAdd(matches, words)
+ let desc = get(a:words, 3, '')
+ let desc = join(split(desc, '#nnnn#', 1), "\n")
+ call add(a:matches, desc)
+endfun
+
" Call `git grep` on the word under the cursor
"
" Shows declarations first, then all matches, in the preview window.
" Activate the omnifunc on Nit files
autocmd FileType nit set omnifunc=NitOmnifunc
+" Define the user command Nitdoc for ease of use
+command -nargs=* Nitdoc call Nitdoc("<args>")
+
let s:script_dir = fnamemodify(resolve(expand('<sfile>:p')), ':h')
var recv = v.init_instance_or_extern(mtype)
- var callsite = self.callsite.as(not null)
+ var callsite = self.callsite
+ if callsite == null then return recv
+
var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
var res2 = v.compile_callsite(callsite, args)
if res2 != null then
toolcontext.error(nmethdef.location, "Syntax error: only a method can be threaded.")
return
end
- if nmethdef.n_signature.n_params.length != 0 then
- toolcontext.error(nmethdef.location, "Syntax error: parametrized method not supported yet.")
- return
- end
+
+ #TODO: check for self calls
+
if nmethdef.n_signature.n_type != null then
toolcontext.error(nmethdef.location, "Syntax error: method with a return value not supported yet.")
return
classname += nmethdef.n_methid.as(AIdMethid).n_id.text
end
- # Create a string corresponding to the threaded class
- var s ="""
+
+ var params = new Array[String]
+ # case if the method has parameters
+ if nmethdef.n_signature.n_params.not_empty then
+ for param in nmethdef.n_signature.n_params do
+ params.add("""
+var {{{param.n_id.text}}} : {{{param.n_type.n_id.text}}}
+
+""")
+ end
+ end
+
+ # String corresponding to the generated class
+ var s="""
class {{{classname}}}
super Thread
+ {{{params.join("\n")}}}
redef fun main do
end
end
assert nullreturn isa AExpr
mainfun.n_block.as(ABlockExpr).n_expr.add(nullreturn)
+
# Create new body for the annotated fun
- var s_newbody ="""
+ var s_newbody : String
+ if nmethdef.n_signature.n_params.not_empty then
+ var init_params = new Array[String]
+ for param in nmethdef.n_signature.n_params do
+ init_params.add(param.n_id.text)
+ end
+ s_newbody ="""
+var thread = new {{{classname}}}({{{init_params.join(",")}}})
+thread.start
+"""
+ else
+ s_newbody = """
var thread = new {{{classname}}}
thread.start
"""
+ end
var newbody = toolcontext.parse_something(s_newbody)
nmethdef.n_block = newbody.as(ABlockExpr)
var mtype = v.unanchor_type(self.recvtype.as(not null))
var recv: Instance = new MutableInstance(mtype)
v.init_instance(recv)
+ var callsite = self.callsite
+ if callsite == null then return recv
+
var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
if args == null then return null
var res2 = v.callsite(callsite, args)
redef fun toolchain(toolcontext, compiler) do return new IOSToolchain(toolcontext, compiler)
end
+private class IosProject
+ super AppProject
+
+ redef fun namespace do return super.to_camel_case
+end
+
private class IOSToolchain
super MakefileToolchain
var ios_project_root: String is noinit
# `app.nit` project for the current compilation target
- var app_project = new AppProject(compiler.modelbuilder, compiler.mainmodule) is lazy
+ var app_project = new IosProject(compiler.modelbuilder, compiler.mainmodule) is lazy
redef fun default_outname do return "{super}.app"
path = Base.lproj/LaunchScreen.xib;
sourceTree = "<group>";
};
- AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */ = {
- isa = PBXFileReference;
- explicitFileType = wrapper.cfbundle;
- includeInIndex = 0;
- path = {{{name}}}Tests.xctest;
- sourceTree = BUILT_PRODUCTS_DIR;
- };
- AF9F83EE1A5F0D21004B62C0 /* Info.plist */ = {
- isa = PBXFileReference;
- lastKnownFileType = text.plist.xml;
- path = Info.plist;
- sourceTree = "<group>";
- };
- AF9F83EF1A5F0D21004B62C0 /* {{{name}}}Tests.m */ = {
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.c.objc;
- path = {{{name}}}Tests.m;
- sourceTree = "<group>";
- };
/* Changing generated files */
"""
);
runOnlyForDeploymentPostprocessing = 0;
};
- AF9F83E61A5F0D21004B62C0 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
isa = PBXGroup;
children = (
AF9F83CE1A5F0D21004B62C0 /* {{{name}}} */,
- AF9F83EC1A5F0D21004B62C0 /* {{{name}}}Tests */,
AF9F83CD1A5F0D21004B62C0 /* Products */,
);
sourceTree = "<group>";
isa = PBXGroup;
children = (
AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */,
- AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */,
);
name = Products;
sourceTree = "<group>";
name = "Supporting Files";
sourceTree = "<group>";
};
- AF9F83EC1A5F0D21004B62C0 /* {{{name}}}Tests */ = {
- isa = PBXGroup;
- children = (
- AF9F83EF1A5F0D21004B62C0 /* {{{name}}}Tests.m */,
- AF9F83ED1A5F0D21004B62C0 /* Supporting Files */,
- );
- path = {{{name}}}Tests;
- sourceTree = "<group>";
- };
- AF9F83ED1A5F0D21004B62C0 /* Supporting Files */ = {
- isa = PBXGroup;
- children = (
- AF9F83EE1A5F0D21004B62C0 /* Info.plist */,
- );
- name = "Supporting Files";
- sourceTree = "<group>";
- };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
productReference = AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */;
productType = "com.apple.product-type.application";
};
- AF9F83E81A5F0D21004B62C0 /* {{{name}}}Tests */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = AF9F83F61A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}Tests" */;
- buildPhases = (
- AF9F83E51A5F0D21004B62C0 /* Sources */,
- AF9F83E61A5F0D21004B62C0 /* Frameworks */,
- AF9F83E71A5F0D21004B62C0 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- AF9F83EB1A5F0D21004B62C0 /* PBXTargetDependency */,
- );
- name = {{{name}}}Tests;
- productName = {{{name}}}Tests;
- productReference = AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */;
- productType = "com.apple.product-type.bundle.unit-test";
- };
/* End PBXNativeTarget section */
/* Begin PBXProject section */
AF9F83CB1A5F0D21004B62C0 = {
CreatedOnToolsVersion = 6.1.1;
};
- AF9F83E81A5F0D21004B62C0 = {
- CreatedOnToolsVersion = 6.1.1;
- TestTargetID = AF9F83CB1A5F0D21004B62C0;
- };
};
};
buildConfigurationList = AF9F83C71A5F0D21004B62C0 /* Build configuration list for PBXProject "{{{name}}}" */;
projectRoot = "";
targets = (
AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */,
- AF9F83E81A5F0D21004B62C0 /* {{{name}}}Tests */,
);
};
/* End PBXProject section */
);
runOnlyForDeploymentPostprocessing = 0;
};
- AF9F83E71A5F0D21004B62C0 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
);
runOnlyForDeploymentPostprocessing = 0;
};
- AF9F83E51A5F0D21004B62C0 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- AF9F83F01A5F0D21004B62C0 /* {{{name}}}Tests.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
/* End PBXSourcesBuildPhase section */
-/* Begin PBXTargetDependency section */
- AF9F83EB1A5F0D21004B62C0 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */;
- targetProxy = AF9F83EA1A5F0D21004B62C0 /* PBXContainerItemProxy */;
- };
-/* End PBXTargetDependency section */
-
/* Begin PBXVariantGroup section */
AF9F83DD1A5F0D21004B62C0 /* Main.storyboard */ = {
isa = PBXVariantGroup;
};
name = Release;
};
- AF9F83F71A5F0D21004B62C0 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- BUNDLE_LOADER = "$(TEST_HOST)";
- FRAMEWORK_SEARCH_PATHS = (
- "$(SDKROOT)/Developer/Library/Frameworks",
- "$(inherited)",
- );
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- INFOPLIST_FILE = {{{name}}}Tests/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
- PRODUCT_NAME = "$(TARGET_NAME)";
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{{name}}}.app/{{{name}}}";
- };
- name = Debug;
- };
- AF9F83F81A5F0D21004B62C0 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- BUNDLE_LOADER = "$(TEST_HOST)";
- FRAMEWORK_SEARCH_PATHS = (
- "$(SDKROOT)/Developer/Library/Frameworks",
- "$(inherited)",
- );
- INFOPLIST_FILE = {{{name}}}Tests/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
- PRODUCT_NAME = "$(TARGET_NAME)";
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{{name}}}.app/{{{name}}}";
- };
- name = Release;
- };
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
);
defaultConfigurationIsVisible = 0;
};
- AF9F83F61A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}Tests" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- AF9F83F71A5F0D21004B62C0 /* Debug */,
- AF9F83F81A5F0D21004B62C0 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- };
/* End XCConfigurationList section */
};
rootObject = AF9F83C41A5F0D21004B62C0 /* Project object */;
end
self.recvtype = recvtype
+ var kind = recvtype.mclass.kind
var name: String
var nid = self.n_id
else
name = "new"
end
+ if name == "intern" then
+ if kind != concrete_kind then
+ v.error(self, "Type Error: Cannot instantiate {kind} {recvtype}.")
+ return
+ end
+ if n_args.n_exprs.not_empty then
+ v.error(n_args, "Type Error: the intern constructor expects no arguments.")
+ return
+ end
+ # Our job is done
+ self.mtype = recvtype
+ return
+ end
+
var callsite = v.get_method(self, recvtype, name, false)
if callsite == null then return
if not callsite.mproperty.is_new then
- var kind = recvtype.mclass.kind
if kind != concrete_kind then
v.error(self, "Type Error: Cannot instantiate {kind} {recvtype}.")
return
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import kernel
+
+class A
+ var i: Int
+ new do
+ var res = new A.intern
+ res.i = 1
+ return res
+ end
+ init do
+ 0.output # not called
+ end
+end
+
+var a = new A
+a.i.output
main
threaded
+10
+parameterized and threaded